Is there any way (possibly a dirty hack) to create an ImmutableArray which will just use a specified array, instead of copying it over?
I have an array which I know won't change, and I want to create an ImmutableArray to allow clients to access my array safely.
Looking at the source code for ImmutableArray, I see the Create method will not help:
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);
}
Edit: There is a request for exactly this feature on GitHub, which also gives the quickest hack to use: https://github.com/dotnet/corefx/issues/28064
There is also another two hacky approaches, both suggested here: https://stackoverflow.com/a/3799030/4418060 (one in answer, one in comment).
First one involves creating a new struct type that mirrors layout of ImmutableArray (which is a single T[]
field) and changing the type of that struct as seen by CLR (runtime). The struct would look like this:
public struct HackImmutableArray<T>
{
public T[] Array;
}
Marshalling:
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;
}
Unsafe casting (nice helpers written here, found in this blog post). Casting uses Unsafe
static class available in System.Runtime.CompilerServices.Unsafe NuGet
using System.Runtime.CompilerServices;
static ImmutableArray<T> HackyMakeImmutable<T>(T[] array)
{
return Unsafe.As<T[], ImmutableArray<T>>(ref array);
}
The second option is "not safe" but quite safe, as we can with certainty assume ImmutableArray's struct layout not to change, being a defining feature, and it'll also be probably much faster than any other solution.