ultima - c# 8
¿Cuál es la diferencia entre sizeof(T) y Unsafe.SizeOf<T>()? (1)
Si bien este método solo utiliza el sizeof
instrucción IL, existe una diferencia con el operador de sizeof
normal, porque este operador no se puede aplicar a tipos arbitrarios:
Se utiliza para obtener el tamaño en bytes para un tipo no administrado. Los tipos no administrados incluyen los tipos incorporados que se enumeran en la tabla que sigue, y también lo siguiente:
Tipos de Enum
Tipos de puntero
Estructuras definidas por el usuario que no contienen ningún campo o propiedad que sean tipos de referencia
Si intentas escribir un análogo de Unsafe.SizeOf
, no funcionará:
public static int SizeOf<T>()
{
// nope, will not compile
return sizeof(T);
}
So Unsafe.SizeOf
levanta las restricciones de Unsafe.SizeOf
del operador y le permite usar instrucciones de tamaño de IL de tipos arbitrarios (incluidos los tipos de referencia para los que devolverá el tamaño de referencia).
En cuanto a la construcción de atributos que se ve en IL, eso no significa que los atributos se instanciarán para cada llamada, eso es solo la sintaxis de IL para asociar atributos con varios miembros (método en este caso).
Ejemplos:
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);
}
Otro ejemplo:
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);
}
En primer lugar, un pequeño aviso legal antes de la pregunta real:
Sé que hay muchas preguntas cerradas / duplicadas con respecto a la diferencia entre el
sizeof
operador y elMarshal.SizeOf<T>
, y entiendo la diferencia entre los dos. Aquí estoy hablando delSizeOf<T>
en la nueva claseUnsafe
Por lo tanto, no estoy seguro de entender la diferencia real entre estas dos operaciones, y si existe una diferencia específica al usar el método en una estructura / clase en particular.
El operador sizeof
toma un nombre de tipo y devuelve el número de bytes administrados que se supone que debe ocupar cuando se lo asigna (es decir, un Int32
devolverá 4, por ejemplo).
El Unsafe.SizeOf<T>
, por otro lado, se implementa en IL como todos los otros métodos en la clase de Unsafe
, y mirando el código, esto es lo que hace:
.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
}
Ahora, si no me equivoco, ¡el código está llamando a sizeof !!T
que es lo mismo que sizeof(T)
(llamando al operador sizeof
con el nombre de tipo T
), por lo que no serían exactamente equivalentes ?
Además, veo que el método también está asignando un objeto inútil (el NonVersionableAttribute
) en la primera línea, así que, ¿no causaría eso que una pequeña cantidad de memoria se asigne también?
Mi pregunta es:
¿Es seguro decir que los dos métodos son perfectamente equivalentes y que, por lo tanto, es mejor usar el operador clásico de
sizeof
, ya que eso también evita la asignación de ese atributo en elSizeOf<T>
? ¿SeSizeOf<T>
esteSizeOf<T>
a la claseUnsafe
solo por conveniencia en este momento?