まず第一に、実際の質問の前の小さな免責事項:
sizeof
演算子と_Marshal.SizeOf<T>
_メソッドの違いに関する多くの閉じた質問や重複した質問があることは知っています。この2つの違いは理解しています。ここでは、新しいUnsafe
クラスの_SizeOf<T>
_メソッドについて話しています。
そのため、これら2つの操作の実際の違い、特にメソッドを構造体/クラスで使用するときに特定の違いがあるかどうかはわかりません。
sizeof
演算子はタイプ名を取り、割り当て時に取ると想定されるmanaged bytesの数を返します(つまり、_Int32
_は4を返します)例)。
一方、_Unsafe.SizeOf<T>
_メソッドは、Unsafe
クラスの他のすべてのメソッドと同様にILに実装されており、コードを見ると次のようになります。
_.method public hidebysig static int32 SizeOf<T>() cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 1
sizeof !!T
ret
}
_
さて、私が間違っていない場合、コードは_sizeof !!T
_を呼び出しているだけで、sizeof(T)
と同じです(sizeof
演算子を型名T
で呼び出します)。それらはまったく同じですか?
また、メソッドも最初の行で役に立たないオブジェクト(NonVersionableAttribute
)を割り当てているので、少量のメモリもヒープに割り当てられませんか?
私の質問は:
2つのメソッドは完全に同等であり、そのため、_
SizeOf<T>
_メソッドでその属性の割り当てを回避するため、従来のsizeof
演算子を使用する方が良いと言えますか?この_SizeOf<T>
_メソッドは、この時点で便宜上、Unsafe
クラスに追加されましたか?
この方法は実際にsizeof
IL命令を使用するだけですが、この演算子は任意の型に適用できないため、通常のsizeof
演算子とは異なります。
アンマネージ型のサイズをバイト単位で取得するために使用されます。アンマネージ型には、次の表に記載されている組み込み型だけでなく、次の型も含まれます。
列挙型
ポインターのタイプ
参照型のフィールドまたはプロパティを含まないユーザー定義の構造体
Unsafe.SizeOf
のアナログを書こうとすると、うまくいきません:
public static int SizeOf<T>()
{
// nope, will not compile
return sizeof(T);
}
したがって、Unsafe.SizeOf
はsizeof
演算子の制限を解除し、IL sizeof
命令を任意の型(参照のサイズを返す参照型を含む)で使用できるようにします。
属性コンストラクトについては、ILで確認できます。つまり、属性が呼び出しごとにインスタンス化されるわけではありません。これは、属性をさまざまなメンバー(この場合はメソッド)に関連付けるためのIL構文です。
例:
public struct Test {
public int Int1;
}
static void Main() {
// works
var s1 = Unsafe.SizeOf<Test>();
// doesn't work, need to mark method with "unsafe"
var s2 = sizeof(Test);
}
もう一つの例:
public struct Test {
public int Int1;
public string String1;
}
static unsafe void Main() {
// works, return 16 in 64bit process - 4 for int, 4 for padding, because
// alignment of the type is the size of its largest element, which is 8
// and 8 for string
var s1 = Unsafe.SizeOf<Test>();
// doesn't work even with unsafe,
// cannot take size of variable of managed type "Test"
// because Test contains field of reference type (string)
var s2 = sizeof(Test);
}