C# 托管结构的大小
NET4.0框架引入了的类。这些类以和的方法为中心。这些文件不是封送的,而是以其在托管内存中的布局形式从文件中复制到文件中 假设我想使用以下方法将两个结构顺序写入内存映射文件: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
[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);