C# 托管结构的大小

C# 托管结构的大小,c#,.net-4.0,C#,.net 4.0,NET4.0框架引入了的类。这些类以和的方法为中心。这些文件不是封送的,而是以其在托管内存中的布局形式从文件中复制到文件中 假设我想使用以下方法将两个结构顺序写入内存映射文件: [StructLayout(LayoutKind.Sequential, Pack = 1)] struct Foo { public char C; public bool B; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct Bar

NET4.0框架引入了的类。这些类以和的方法为中心。这些文件不是封送的,而是以其在托管内存中的布局形式从文件中复制到文件中

假设我想使用以下方法将两个结构顺序写入内存映射文件:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct Foo
{
    public char C;
    public bool B;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct Bar
{
}

static void Write<T1, T2>(T1 item1, T2 item2)
    where T1 : struct
    where T2 : struct
{
    using (MemoryMappedFile file = MemoryMappedFile.CreateNew(null, 32))
    using (MemoryMappedViewAccessor accessor = file.CreateViewAccessor())
    {
        accessor.Write<T1>(0L, ref item1);  //  <-- (1)
        accessor.Write<T2>(??, ref item2);  //  <-- (2)
    }
}

static void Main()
{
    Foo foo = new Foo { C = 'α', B = true };
    Bar bar = new Bar { };
    Write(foo, bar);
}
[StructLayout(LayoutKind.Sequential,Pack=1)]
结构Foo
{
公共字符C;
公共图书馆;
}
[StructLayout(LayoutKind.Sequential,Pack=1)]
结构条
{
}
静态无效写入(T1项1、T2项2)
其中T1:struct
其中T2:struct
{
使用(MemoryMappedFile=MemoryMappedFile.CreateNew(null,32))
使用(MemoryMappedViewAccessor=file.CreateViewAccessor())
{

accessor.Write(0L,ref item1);//似乎没有文档/公共的方法来访问
MemoryMappedViewAccessor
类使用的内部
SizeOfType
函数,因此获取这些结构的大小的最实用的方法是使用如下反射:

static readonly Func<Type, uint> SizeOfType = (Func<Type, uint>)Delegate.CreateDelegate(typeof(Func<Type, uint>), typeof(Marshal).GetMethod("SizeOfType", BindingFlags.NonPublic | BindingFlags.Static));

static void Write<T1, T2>(T1 item1, T2 item2)
    where T1 : struct
    where T2 : struct
{
    using (MemoryMappedFile file = MemoryMappedFile.CreateNew(null, 32))
    using (MemoryMappedViewAccessor accessor = file.CreateViewAccessor())
    {
        accessor.Write(0, ref item1);
        accessor.Write(SizeOfType(typeof(T1)), ref item2);
    }
}
static readonly Func SizeOfType=(Func)Delegate.CreateDelegate(typeof(Func),typeof(Marshal.GetMethod(“SizeOfType”,BindingFlags.NonPublic | BindingFlags.static));
静态无效写入(T1项1、T2项2)
其中T1:struct
其中T2:struct
{
使用(MemoryMappedFile=MemoryMappedFile.CreateNew(null,32))
使用(MemoryMappedViewAccessor=file.CreateViewAccessor())
{
写入(0,参考项1);
写入(SizeOfType(typeof(T1)),参考项2);
}
}

您可以使用Emit访问Sizeof操作码并绕过编译器对获取Sizeof(T)的限制:

var sizeOfMethod=newdynamicmethod(
“GetManagedSizeImpl”
,类型(uint)
无效的
,对);
var genSizeOf=sizeOfMethod.GetILGenerator();
Emit(opcode.Sizeof,typeof(T));
genSizeOf.Emit(操作码Ret);
var sizeofffunction=(Func)sizeOfMethod.CreateDelegate(typeof(Func));
// ...
int size=checked((int)sizeofffunction());

1.本页的一个答案建议使用内部函数
Marshal.SizeOfType
,但这仅适用于不包含任何托管引用的结构。在.NET 4.7上,当传递引用(
)时,它会抛出一个
ArgumentException
类型,或包含嵌入引用的
struct
类型

2.这里的另一个答案建议使用
sizeof
操作码。这适用于所有
struct
值类型,包括泛型和嵌入引用的值类型,但对于引用类型,它总是返回
IntPtr.Size
(即值
4
8
),而不是托管类(实例)的实际布局大小。这可能是您想要的,具体取决于您的情况。请注意,通过将包含单个嵌入引用(句柄)的结构的大小写与单个引用(句柄)本身合并,这种结果会优雅地降级

调用
sizeof
IL指令的更简单方法是通过包:

4.因此——仍然是前面的警告——要从其
类型
句柄中获取任何引用或值类型(包括包含嵌入引用的引用)的实例布局大小,请结合方法#2和#3:

int instance\u layout\u bytes=typeof(T).IsValueType?
不安全。Sizeof():
Marshal.ReadInt32(typeof(T).TypeHandle.Value,4);



相关:

这就是我目前正在做的。我希望有一个更干净的解决方案。在我看来,依靠内部的、未记录的方法并不是一个好主意。根据我的经验,这通常已经足够好了(至少在服务器应用程序中)而且,这通常是一开始做这件事的唯一方法。Бзззззззззззззззззззз。
var sizeOfMethod = new DynamicMethod(
    "GetManagedSizeImpl"
,   typeof(uint)
,   null
,   true);
var genSizeOf = sizeOfMethod.GetILGenerator();
genSizeOf.Emit(OpCodes.Sizeof, typeof(T));
genSizeOf.Emit(OpCodes.Ret);
var sizeOfFunction = (Func<uint>)sizeOfMethod.CreateDelegate(typeof(Func<uint>));

// ...
int size = checked((int)sizeOfFunction());
int struct_layout_bytes = Unsafe.Sizeof<T>();
int class_layout_bytes = Marshal.ReadInt32(typeof(T).TypeHandle.Value, 4)
int instance_layout_bytes = typeof(T).IsValueType ? 
                                Unsafe.Sizeof<T>() : 
                                Marshal.ReadInt32(typeof(T).TypeHandle.Value, 4);