代码之家  ›  专栏  ›  技术社区  ›  Yair Halberstadt

在不复制C的情况下创建不变数组#

  •  3
  • Yair Halberstadt  · 技术社区  · 8 年前

    查看不可变数组的源代码 http://source.roslyn.io/#System.Collections.Immutable/System/Collections/Immutable/ImmutableArray.cs

    public static ImmutableArray<T> Create<T>(params T[] items)
    {
        if (items == null)
        {
            return Create<T>();
        }
    
        // We can't trust that the array passed in will never be mutated by the caller.
        // The caller may have passed in an array explicitly (not relying on compiler params keyword)
        // and could then change the array after the call, thereby violating the immutable
        // guarantee provided by this struct. So we always copy the array to ensure it won't ever change.
        return CreateDefensiveCopy(items);
    }
    

    现在我有了一个我知道不会改变的数组,我想创建一个不变的数组来允许客户机安全地访问我的数组。

    有没有办法(可能是一个肮脏的黑客)创建一个不变的数组,它只使用我的原始数组,而不是复制它?

    编辑

    刚刚看到了这个功能的请求。它还提供了最快的黑客使用: https://github.com/dotnet/corefx/issues/28064

    5 回复  |  直到 8 年前
        1
  •  2
  •   Amiś    8 年前

    https://stackoverflow.com/a/3799030/4418060

    T[]

    public struct HackImmutableArray<T>
    {
        public T[] Array;
    }
    
    1. static ImmutableArray<T> HackyMakeImmutable<T>(T[] array)
      {
          var arrayObject = (object)new HackImmutableArray<T> { Array = array };
          var handle = GCHandle.Alloc(arrayObject, GCHandleType.Pinned);
          var immutable = (ImmutableArray<T>)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
          handle.Free();
          return immutable;
      }
      
    2. written here this blog post Unsafe System.Runtime.CompilerServices.Unsafe NuGet

      using System.Runtime.CompilerServices;
      
      static ImmutableArray<T> HackyMakeImmutable<T>(T[] array)
      {
          return Unsafe.As<T[], ImmutableArray<T>>(ref array);
      }
      

        2
  •  6
  •   xanatos    8 年前

    ImmutableArray.CreateBuilder<> .MoveToImmutable() ImmutableArray<> Builder

    var builder = ImmutableArray.CreateBuilder<int>(4);
    builder.Add(1);
    builder.Add(2);
    builder.Add(3);
    builder.Add(4);
    ImmutableArray<int> array = builder.MoveToImmutable();
    

    builder.Capacity != builder.Count

    .ToImmutable()

        3
  •  1
  •   MineR    8 年前

    public static ImmutableArray<T> GetImmutableArray<T>(T[] arr)
    {
        var immutableArray = ImmutableArray.Create(new T[0]);
        var boxed = ((object) immutableArray);
        var t = boxed.GetType();
        var fi = t.GetField("array", BindingFlags.NonPublic | BindingFlags.Instance);
        fi.SetValue(boxed, arr);
        return (ImmutableArray<T>)boxed;
    }
    

    var arr = new int[] { 1, 2, 3 };
    Console.WriteLine("Arr: " + string.Join(",", arr)); //Arr: 1,2,3
    var imm = GetImmutableArray(arr);
    Console.WriteLine("ImmutableArray: " + string.Join(",", imm)); //ImmutableArray: 1,2,3
    arr[0] = 234;
    imm[0] = 235; //Compile Error
    Console.WriteLine("ImmutableArray: " + string.Join(",", imm)); //ImmutableArray: 234,2,3
    

        4
  •  0
  •   InBetween    8 年前

    ImmutableArray<T> IReadOnlyList<T>

    public class ImmutableArrayWrapper<T>: IReadOnlyList<T>
    {
         public static ImmutableArrayWrapper<T> Wrap(T[] array)
             => new ImmutableArrayWrapper(array);
    
        private readonly T[] innerArray;
    
        private ImmutableArrayWrapper(T[] arr) {
             if (arr == null)
                 throw new ArgumentNullException();
    
             innerArray = arr; }
    
        public int Count => innerArray.Count();
        public T this[int index] => innerArray[index];
    
        //IEnumerable<T>...
    }
    

        5
  •  0
  •   Yair Halberstadt    8 年前

    https://github.com/dotnet/corefx/issues/28064

    ImmutableArray<T> im = Unsafe.As<T[], ImmutableArray<T>>(ref array);