在http://source.roslyn.io/#System.Collections.Immutable/System/Collections/Immutable/ImmutableArray.cs上查看ImmutableArray的源代码
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);
}
Run Code Online (Sandbox Code Playgroud)
现在我有一个我知道不会改变的数组,我想创建一个ImmutableArray来允许客户端安全地访问我的数组.
是否有任何方法(可能是一个肮脏的黑客)创建一个ImmutableArray只会使用我的原始数组,而不是复制它?
编辑
刚看到这个请求就是这个功能.它还提供最快的黑客使用:https://github.com/dotnet/corefx/issues/28064
如果你知道数组的确切长度,你可以使用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();
Run Code Online (Sandbox Code Playgroud)
如果,该方法.MoveToImmutable()将抛出异常builder.Capacity != builder.Count
请注意,构建器的其他方法(如.ToImmutable())将创建该数组的副本.
在.NET 8预览版中不再需要使用Unsafe。
他们公开了一些额外的方法来访问内部构造函数。
使用ImmutableCollectionsMarshal.AsImmutableArray<T>:
ImmutableArray<T> im = ImmutableCollectionsMarshal.AsImmutableArray(array);
Run Code Online (Sandbox Code Playgroud)
还有另外两种黑客方法,均在这里建议:/sf/answers/265932131/(一种在答案中,一种在评论中)。
第一个涉及创建一个新的结构类型,该结构类型反映 ImmutableArray(这是单个T[]字段)的布局,并更改 CLR(运行时)所看到的该结构的类型。该结构如下所示:
public struct HackImmutableArray<T>
{
public T[] Array;
}
Run Code Online (Sandbox Code Playgroud)
编组:
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;
}
Run Code Online (Sandbox Code Playgroud)不安全的转换(这里写的好帮手,可以在这篇博客文章中找到)。转换使用System.Runtime.CompilerServices.Unsafe NuGetUnsafe中可用的静态类
using System.Runtime.CompilerServices;
static ImmutableArray<T> HackyMakeImmutable<T>(T[] array)
{
return Unsafe.As<T[], ImmutableArray<T>>(ref array);
}
Run Code Online (Sandbox Code Playgroud)第二个选项“不安全”,但相当安全,因为我们可以肯定地假设 ImmutableArray 的结构布局不会改变,这是一个定义功能,而且它也可能比任何其他解决方案快得多。