通用结构的大小 [英] Size of generic structure

查看:126
本文介绍了通用结构的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



所以我写道:

pre $ public static class HelperMethods
{
static HelperMethods ()
{
SizeOfType = createSizeOfFunc();


public static int SizeOf< T>()
{
return SizeOfType(typeof(T));
}

public static readonly Func< Type,int> SizeOfType = null;

private static Func< Type,int> 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); //需要成为il.Emit(OpCodes.Sizeof,typeof(something))
il.Emit(OpCodes.Ret);
$ b $ var func =(Func< Type,int>)dm.CreateDelegate(typeof(Func< Type,int>));
返回func;
}
}

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

解决方案

计算大小是充满了问题的东西,因为你需要知道在上下文中什么是有意义的你正在使用它。我认为当参数是一个泛型结构时,有一个很好的理由让 Marshal.SizeOf 抛出,但我不知道它是什么。



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

  public class A {int x ,Y,Z; } 
public struct B {int x,y,z,w,a,b; }
public struct C< T> {Guid g; T b,c,d,e,f; }
$ b $ public class Program
{
public static void Main(string [] args)
{
Console.WriteLine(IntPtr.Size); //在x86上== 4
Console.WriteLine(SizeHelper.SizeOf(typeof(C< double>))); //在x86上打印56
Console.WriteLine(SizeHelper.SizeOf(typeof(C< int>))); //在x86上打印36
}
}

static class SizeHelper
{
private static Dictionary< Type,int> size = new Dictionary< Type,int>();

public static int SizeOf(Type type)
{
int size;
if(sizes.TryGetValue(type,out size))
{
return size;
}

size = SizeOfType(type);
sizes.Add(type,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);


编辑



据我所知,无法制作可以缓存的非泛型委托。 SizeOf 操作码需要一个元数据令牌。它不会从评估堆栈中获得一个值。



其实下面的代码也适用。我不知道为什么当类型是泛型结构但是 Marshal.SizeOf(Object)时,为什么 Marshal.SizeOf(Type)抛出一个参数异常。

  public static int SizeOf< T>()其中T:struct 
{
返回Marshal.SizeOf(default(T));
}


I need to find out a size of a generic structure (I can not do it like sizeof(T) or using Marshal.SizeOf(...) 0> gives me an error)

So I wrote:

public static class HelperMethods
{
    static HelperMethods()
    {
        SizeOfType = createSizeOfFunc();
    }

    public static int SizeOf<T>()
    {
        return SizeOfType(typeof(T));
    }

    public static readonly Func<Type, int> SizeOfType = null;

    private static Func<Type, int> 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<Type, int>)dm.CreateDelegate(typeof(Func<Type, int>));
        return func;
    }
}

A diffuclty is that il.Emit(OpCodes.Sizeof) needs an argument which I can not pass it during the method (SizeOfType) creation. How can I pass a parameter which is on stack to il.Emit(OpCodes.Sizeof) using IL ? (or a different solution but I want to cache a function (delegate) not a result what is proposed in the 2nd answer)

解决方案

Computing size is something that is fraught with problems because you need to know what is meaningful in the context you are using it. I'd assume there is a good reason for Marshal.SizeOf to throw when the argument is a generic struct, but I don't know what it is.

With that caveat, this code seems to work and gives similar results to Marshal.SizeOf for non-generic structs. It generates a new dynamic method that gets the size via the sizeof IL opcode for the type. It then caches the result (since generating a dynamic method is some what expensive) for future use.

public class A { int x,y,z; }
public struct B { int x,y,z,w,a,b; }
public struct C<T> { 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<double>))); // prints 56 on x86
        Console.WriteLine(SizeHelper.SizeOf(typeof(C<int>))); // prints 36 on x86
    }
}

static class SizeHelper
{
    private static Dictionary<Type, int> sizes = new Dictionary<Type, int>();

    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);
    }
}

Edit

As far as I can tell there is no way to make non-generic delegate that you can cache. The SizeOf opcode requires a metadata token. It does not take a value from the evaluation stack.

Actually the code below works as well. I'm not sure why Marshal.SizeOf(Type) throws an argument exception when the type is generic structure but Marshal.SizeOf(Object) does not.

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

这篇关于通用结构的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆