听起来,IL sizeof
指令可能是您所需要的。sizeof
指令由 C# sizeof
运算符在幕后使用,但由于某些原因,IL 版本的限制更少。
ECMA CLI 规范(第 III 部分,第 4.25 节)对 sizeof
指令有以下描述:
返回类型的大小(以字节为单位)。typeTok可以是泛型参数、引用类型或值类型。
对于引用类型,返回的大小是相应类型的引用值的大小,而不是由引用值引用的对象中存储的数据的大小。
[解释:值类型的定义在CIL生成时和加载执行时可能会发生变化。因此,在生成CIL时并不总是知道类型的大小。sizeof指令允许CIL代码在运行时确定大小,而无需调用框架类库。计算可以完全在运行时或在CIL到本机代码编译时进行。sizeof返回每个元素在此类型的数组中占用的总大小,包括实现选择添加的任何填充。具体来说,数组元素相距sizeof个字节。]
您应该能够通过一些简单的运行时代码生成获得sizeof指令。
Console.WriteLine("Entry is " + TypeHelper.SizeOf(typeof(Entry)) + " bytes.");
public static class TypeHelper
{
public static int SizeOf<T>(T? obj) where T : struct
{
if (obj == null) throw new ArgumentNullException("obj");
return SizeOf(typeof(T?));
}
public static int SizeOf<T>(T obj)
{
if (obj == null) throw new ArgumentNullException("obj");
return SizeOf(obj.GetType());
}
public static int SizeOf(Type t)
{
if (t == null) throw new ArgumentNullException("t");
return _cache.GetOrAdd(t, t2 =>
{
var dm = new DynamicMethod("$", typeof(int), Type.EmptyTypes);
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Sizeof, t2);
il.Emit(OpCodes.Ret);
var func = (Func<int>)dm.CreateDelegate(typeof(Func<int>));
return func();
});
}
private static readonly ConcurrentDictionary<Type, int>
_cache = new ConcurrentDictionary<Type, int>();
}
TKey
和TValue
的类型,大小会发生变化。 - George DuckettEntry<char, bool>
的大小将与Entry<string, decimal>
不同。 - CorakMarshal.SizeOf(new Entry<string, decimal>())
会抛出ArgumentException异常:"类型“Entry`2[System.String,System.Decimal]”无法作为非托管结构体进行封送;无法计算有意义的大小或偏移量。" - Corak