我想估计含一般类型参数结构的数组的大小,在这种情况下,词典条目结构。 要做到这一点,我需要的结构的大小。
struct Entry
{
int hash;
int next;
TKey key;
TValue value;
}
我怎样才能在这个结构的字节大小?
编辑
似乎使用Marshal.SizeOf
是有问题的。 路过的结构类型将引发一个异常说,参数不能为泛型类型定义。
如果我不是调用了一个实例,例如超载Marshal.SizeOf(default(Entry))
如果两个泛型类型参数是值类型,它将工作。 如果通用参数被例如<int, object>
那么这会引发异常
Dictionary`2 +条目[System.Int32,System.Object的]”不能被编组为不接受管理结构; 没有有意义的大小或偏移量可以被计算。
这听起来像IL sizeof
指令可能是你所需要的。 该sizeof
指令是由C#中使用sizeof
操作符幕后的,但IL版本有某种原因的限制更少。
在ECMA CLI规范 (分区III,节4.25)具有的这种描述sizeof
指令:
返回的大小,以字节为单位的类型。 typeTok
可为通用参数,引用类型或值类型。
对于引用类型,返回的尺寸为相应的类型,而不是存储在由参考值称为对象的数据的大小的基准值的大小。
[ 理由:值类型的定义可以生成CIL的时间和它被加载用于执行的时间之间改变。 因此,该类型的大小并不总是产生CIL时已知的。 该sizeof
指令允许CIL代码,以确定在运行时的大小,而无需调用到Framework类库。 计算可以在运行时或在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>();
}
近似尺寸将求和的hash
(4个字节(32位架构))+ next
(4个字节(32位架构))+ TKey
(如果4个参考类型字节的指针(32位体系结构)中,如果值键入尺寸在递归计算出的值类型))+的TValue
(同TKey
)
要么
简单地使用Marshal.SizeOf方法。
您也可以使用Marshal.ReadIntPtr(type.TypeHandle.Value, 4)
它返回的管理对象的基本实例的大小。 见http://msdn.microsoft.com/en-us/magazine/cc163791.aspx有关运行时内存布局的详细信息。
(我写了这个之后,我注意到,该方法在理论基础 LukeH引述预期)
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]);
}
我相当肯定的是牵制和扔掉一个小数组比动态编译便宜。 加上通用类的静态字段是一个伟大的方式有类型安全的每个类型的数据...不需要一个ConcurrentDictionary
。