はじめに
今回はRuntimeHelpers.IsReferenceOrContainsReferences<T>
について紹介をしたいと思います。
概要
public static bool IsReferenceOrContainsReferences<T> ();
指定された型が参照型であるか、または参照を含む値型であるかを示す値を返します。
使い方
public static void Main(string[] args) { // True Console.WriteLine(RuntimeHelpers.IsReferenceOrContainsReferences<SampleClass>()); // True Console.WriteLine(RuntimeHelpers.IsReferenceOrContainsReferences<ContainsReferenceStruct>()); // False Console.WriteLine(RuntimeHelpers.IsReferenceOrContainsReferences<NoContainsReferencesStruct>()); } public class SampleClass { public int Value; } public struct ContainsReferenceStruct { public int Value; public string Str; } public struct NoContainsReferencesStruct { public int Value; }
考察
RuntimeHelpers.IsReferenceOrContainsReferences
がfalse
の場合は、データがメモリの上に一列に並ぶことが保証されています。
public static void Main(string[] args) { var sample = new Sample() { X = 10, Y = 2, Z = 999, }; // a, 0, 0, 0 Console.WriteLine(string.Join(",", BitConverter.GetBytes(10).Select(x => x.ToString("x")))); // 2, 0, 0, 0 Console.WriteLine(string.Join(",", BitConverter.GetBytes(2).Select(x => x.ToString("x")))); // e3, 3, 0, 0 Console.WriteLine(string.Join(",", BitConverter.GetBytes(999).Select(x => x.ToString("x")))); if (!RuntimeHelpers.IsReferenceOrContainsReferences<Sample>()) { // sampleが利用しているバイト数だけメモリを確保する // new byte[]と同じくマネージドメモリを確保するが、配列の要素はゼロ初期化されていないのでちょっと早い var array = GC.AllocateUninitializedArray<byte>(Unsafe.SizeOf<Sample>()); // arrayのメモリ領域にsampleを書き込む Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(array.AsSpan()), sample); // 中身がちゃんと書き込まれているかチェックする // a,0,0,0,2,0,0,0,e7,3,0,0 Console.WriteLine(string.Join(",", array.Select(x => x.ToString("x")))); } } public struct Sample { public int X; public int Y; public int Z; }