通用结构的大小

我需要找出一个通用结构的大小(我不能像sizeof(T)或使用Marshal.SizeOf(…)0>给我一个错误)

所以我写道:

public static class HelperMethods { static HelperMethods() { SizeOfType = createSizeOfFunc(); } public static int SizeOf() { return SizeOfType(typeof(T)); } public static readonly Func SizeOfType = null; private static Func createSizeOfFunc() { var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { typeof(Type) }); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Sizeof); //needs to be il.Emit(OpCodes.Sizeof, typeof(something)) il.Emit(OpCodes.Ret); var func = (Func)dm.CreateDelegate(typeof(Func)); return func; } } 

一个不同之处是il.Emit(OpCodes.Sizeof)需要一个参数,在创建方法(SizeOfType)时我无法传递它。 如何使用IL将堆栈中的参数传递给il.Emit(OpCodes.Sizeof)? (或者是一个不同的解决方案,但我想缓存一个函数(委托)而不是第二个答案中提出的结果)

计算大小是充满问题的因素,因为您需要知道在使用它的上下文中有什么意义。 我假设Marshal.SizeOf有一个很好的理由在参数是一个通用结构时抛出,但我不知道它是什么。

有了这个警告,这个代码似乎可以工作,并为Marshal.SizeOf提供与非generics结构相似的结果。 它生成一个新的动态方法,通过该类型的IL操作码的大小来获取大小。 然后它将缓存结果(因为生成动态方法是一些昂贵的)以供将来使用。

 public class A { int x,y,z; } public struct B { int x,y,z,w,a,b; } public struct C { Guid g; T b,c,d,e,f; } public class Program { public static void Main(string[] args) { Console.WriteLine(IntPtr.Size); // on x86 == 4 Console.WriteLine(SizeHelper.SizeOf(typeof(C))); // prints 56 on x86 Console.WriteLine(SizeHelper.SizeOf(typeof(C))); // prints 36 on x86 } } static class SizeHelper { private static Dictionary sizes = new Dictionary(); public static int SizeOf(Type type) { int size; if (sizes.TryGetValue(type, out size)) { return size; } size = SizeOfType(type); sizes.Add(type, size); return size; } private static int SizeOfType(Type type) { var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { }); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Sizeof, type); il.Emit(OpCodes.Ret); return (int)dm.Invoke(null, null); } } 

编辑

据我所知,没有办法让你可以缓存的非generics委托。 SizeOf操作码需要元数据令牌。 它不会从评估堆栈中获取值。

实际上下面的代码也适用。 我不确定为什么Marshal.SizeOf(Type)抛出一个参数exception,当类型是通用结构但Marshal.SizeOf(Object)没有。

  public static int SizeOf() where T : struct { return Marshal.SizeOf(default(T)); } 

上面的思考更进了一步,我到了:

 public static class TypeSize { public readonly static int Size; static TypeSize() { var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { }); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Sizeof, typeof(T)); il.Emit(OpCodes.Ret); Size = (int)dm.Invoke(null, null); } } 

…我认为这是解决问题的最有效方法。

您的目标似乎是在编译时从函数返回类型Func解析参数Type 。 在编译时不知道此信息,并且没有明显的方法在运行时使用reflection来解析此信息。

我没有看到返回动态方法的好处,而不是调用动态方法并立即返回结果。 鉴于您没有给出任何上下文,我会提出明显的解决方案,立即返回值。 如果您的担忧在于性能,那么只需将结果缓存在字典中。

 public static class GlobalExtensions { public static int SizeOf() { return SizeOf(typeof (T)); } public static int SizeOf(this Type type) { var dynamicMethod = new DynamicMethod("SizeOf", typeof(int), Type.EmptyTypes); var generator = dynamicMethod.GetILGenerator(); generator.Emit(OpCodes.Sizeof, type); generator.Emit(OpCodes.Ret); var function = (Func) dynamicMethod.CreateDelegate(typeof(Func)); return function(); } } 

使用扩展方法可以利用一些很好的语法。 您现在可以使用以下代码继续获取通用结构或类的大小:

 var size = TypeExtensions.SizeOf>(); //alternative syntax... size = typeof (Example).SizeOf();