web-dev-qa-db-ja.com

sizeof(T)とUnsafe.SizeOf <T>()の違いは何ですか?

まず第一に、実際の質問の前の小さな免責事項:

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クラスに追加されましたか?

32
Sergio0694

この方法は実際にsizeof IL命令を使用するだけですが、この演算子は任意の型に適用できないため、通常のsizeof演算子とは異なります。

アンマネージ型のサイズをバイト単位で取得するために使用されます。アンマネージ型には、次の表に記載されている組み込み型だけでなく、次の型も含まれます。

列挙型

ポインターのタイプ

参照型のフィールドまたはプロパティを含まないユーザー定義の構造体

Unsafe.SizeOfのアナログを書こうとすると、うまくいきません:

public static int SizeOf<T>()
{
    // nope, will not compile
    return sizeof(T);
}

したがって、Unsafe.SizeOfsizeof演算子の制限を解除し、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);                        
} 
24
Evk