Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有泛型类型字段的结构的大小_C#_.net_Struct - Fatal编程技术网

C# 具有泛型类型字段的结构的大小

C# 具有泛型类型字段的结构的大小,c#,.net,struct,C#,.net,Struct,我想估计包含泛型类型参数的结构数组的大小,在本例中是字典条目结构。为此,我需要结构的大小 struct Entry { int hash; int next; TKey key; TValue value; } 如何获取此结构的大小(以字节为单位) 编辑 使用Marshal.SizeOf似乎有问题。传递结构的类型将引发异常,说明参数不能是泛型类型定义 如果我改为调用获取实例的重载,例如,Marshal.SizeOf(default(Entry))如果两个泛型类型参数都是

我想估计包含泛型类型参数的结构数组的大小,在本例中是字典条目结构。为此,我需要结构的大小

struct Entry
{
   int hash;
   int next;
   TKey key;
   TValue value;
}
如何获取此结构的大小(以字节为单位)

编辑

使用
Marshal.SizeOf
似乎有问题。传递结构的类型将引发异常,说明参数不能是泛型类型定义

如果我改为调用获取实例的重载,例如,
Marshal.SizeOf(default(Entry))
如果两个泛型类型参数都是值类型,它将起作用。如果泛型参数为,例如
,则会引发此异常

字典“2+条目[System.Int32,System.Object]”不能作为 非托管结构;无法计算有意义的大小或偏移量


近似的大小将是
散列
(4字节(32位体系结构))+
下一个
(4字节(32位体系结构))+
TKey
(如果指针引用类型为4字节(32位体系结构),如果值类型为递归计算的值类型的大小))+
TValue
(同
TKey


只需使用方法。

您也可以使用
Marshal.ReadIntPtr(type.TypeHandle.Value,4)
。它返回托管对象的基本实例大小。有关运行时内存布局的更多信息,请参阅。

听起来IL指令可能是您所需要的。C#运算符在后台使用
sizeof
指令,但由于某些原因,IL版本的限制较少

(第三部分,第4.25节)对
sizeof
指令进行了如下描述:

返回类型的大小(以字节为单位)。
typeTok
可以是泛型 参数、引用类型或值类型

对于引用类型,返回的大小是引用的大小 对应类型的值,而不是存储在中的数据的大小 由引用值引用的对象

[理由:值类型的定义可以在 生成CIL的时间和加载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>();
}
Console.WriteLine(“条目是”+TypeHelper.SizeOf(typeof(条目))+“字节”);
// ...
公共静态类TypeHelper
{
公共静态int-SizeOf(T?obj),其中T:struct
{
如果(obj==null)抛出新的ArgumentNullException(“obj”);
返回SizeOf(类型(T?);
}
公共静态int SizeOf(T obj)
{
如果(obj==null)抛出新的ArgumentNullException(“obj”);
返回SizeOf(obj.GetType());
}
公共静态int-SizeOf(t型)
{
如果(t==null)抛出新的ArgumentNullException(“t”);
return\u cache.GetOrAdd(t,t2=>
{
var dm=new DynamicMethod(“$”,typeof(int),Type.EmptyTypes);
ILGenerator il=dm.GetILGenerator();
il.Emit(opcode.Sizeof,t2);
发射(操作码Ret);
var func=(func)dm.CreateDelegate(typeof(func));
返回func();
});
}
私有静态只读ConcurrentDictionary
_缓存=新的ConcurrentDictionary();
}
(在我写了这篇文章之后,我注意到LukeH引用的理由中预期了这种方法)

struct Pin:IDisposable
{
公共把手;
公共Pin(对象o){pinHandle=GCHandle.Alloc(o,GCHandleType.pinted);}
公共空间处置()
{
pinHandle.Free();
}
}
静态类元素大小
{
私有静态int-CalcSize(T[]testarray)
{
使用(引脚p=新引脚(测试阵列))
return(int)(Marshal.unsafeaddrofpindedarrayelement(testarray,1).ToInt64()
-unsafeaddroffinnedArrayement(testarray,0.ToInt64());
}
静态公共只读int字节=CalcSize(新的T[2]);
}

我相当确信,固定和丢弃一个小数组比动态编译便宜。加上泛型类中的静态字段是每个类型数据都具有类型安全性的好方法……甚至不需要
ConcurrentDictionary

这是可能的;当然这取决于
TKey
TValue
的类型我会改变。如果TKey和TValue是泛型,你现在不能预先计算它们的类型,所以我认为不可能计算大小。“结构的大小”。如果你使用泛型,编译器基本上会创建尽可能多的不同结构/类,就像你使用不同的TKey/TValue组合一样。因此,没有一个结构有一个大小,但是(可能)许多不同的结构都有各自的大小。因此
条目
的大小将不同于
条目
。更好的是
Marshal.SizeOf(new Entry())
抛出ArgumentException:“键入'Entry`2[System.String,System.Decimal]'不能作为非托管结构封送;无法计算有意义的大小或偏移量。“是的,我想用类型已知的参数得到结构的大小,也就是说,在运行时。指针的大小是4字节?现在是2013年,而你仍然在假设一个32位的体系结构?@Damien_the_Insiever:你不会相信,但我们在公司中仍然使用XP,所以…我
struct Pin : IDisposable
{
    public GCHandle pinHandle;
    public Pin(object o) { pinHandle = GCHandle.Alloc(o, GCHandleType.Pinned); }

    public void Dispose()
    {
        pinHandle.Free();
    }
}

static class ElementSize<T>
{
    private static int CalcSize(T[] testarray)
    {
      using (Pin p = new Pin(testarray))
        return (int)(Marshal.UnsafeAddrOfPinnedArrayElement(testarray, 1).ToInt64()
                   - Marshal.UnsafeAddrOfPinnedArrayElement(testarray, 0).ToInt64());
    }

    static public readonly int Bytes = CalcSize(new T[2]);
}