Add public API MemoryMarshal.GetArrayDataReference by GrabYourPitchforks · Pull Request #1036 · dotnet/runtime (original) (raw)
Resolves https://github.com/dotnet/corefx/issues/36133.
This introduces a new public API public static MemoryMarshal.GetRawArrayData<T>(T[] array) : ref T
. It's similar in spirit to the existing MemoryMarshal.GetReference
, with the following explicit behaviors:
- The method returns a reference to the first element in the array; or, if the input array is zero-length, a reference to where the first element would have been. This reference can be used for address comparisons (such as
Unsafe.IsAddressGreaterThan
) in all cases, but it can only be safely dereferenced in the case where the input array is not zero-length. - No argument null check is performed. If a null reference is provided, the method throws NRE. Contrast this against
MemoryMarshal.GetReference
, which will return nullptr (as a T&) when given aSpan<T>
generated from a nullT[]
. - No array variance check is performed. It's possible to pass a
string[]
to this API and to get a ref object back. Such a thing can be safely dereferenced (subject to the zero-length argument caveat mentioned above), but it must never be written to unless the caller knows that the value being written is compatible with the actual type of the array.
For an example of that last bullet point above:
/* using standard "safe" ref semantics */ string[] strArray = new string[] { "Hello!" }; ref string s = ref strArray[0]; // succeeds object[] objArray = strArray; // succeeds, actual type is string[] ref object o = ref array[0]; // throws ArrayTypeMismatchException due to runtime array variance checks
/* using "unsafe" GetRawArrayData */ object[] array = new string[] { "Hello!" }; // actual type is string[] ref object o = ref MemoryMarshal.GetRawArrayData(array); // succeeds Console.WriteLine(o); // dereferencing 'o' is OK as long as array.Length >= 1 o = new object(); // !! DON'T DO THIS !! - this is a type safety violation
In API review, we had decided on naming this method MemoryMarshal.GetReference
to match the existing span-based overloads. However, after some experimentation I realized that the logic we based our decision on was faulty - see my comment at https://github.com/dotnet/corefx/issues/36133#issuecomment-566834006 for more info. So for this PR I've reverted back to the originally suggested name. If we want to keep the GetReference
name anyway I can do that - just let me know and I can update this PR.