在.NET Core中,只有一个通用方法Marshal.SizeOf<T>()
可用(Marshal.SizeOf(Type t)
已弃用)。但我想枚举一个类的所有属性并获得它们的元素大小。我该怎么办?
这是我的代码:(实际上并不是我的,但我试图移植到.NET Core的代码)
来自https://github.com/kapetan/dns/blob/master/DNS/Protocol/Marshalling/Struct.cs并进行修改
private static byte[] ConvertEndian<T>(byte[] data)
{
var fields = typeof(T).GetRuntimeFields().Where(f => f.IsStatic == false);
EndianAttribute endian = typeof(T).GetTypeInfo().GetCustomAttribute<EndianAttribute>();
foreach (FieldInfo field in fields)
{
if (endian == null && field.GetCustomAttribute<EndianAttribute>(false) == null)
{
continue;
}
int offset = Marshal.OffsetOf<T>(field.Name).ToInt32();
// *** This is deprecated ***
// int length = Marshal.SizeOf(field.FieldType);
// *** This doesn't work at all ***
int length = field.FieldType.GetTypeInfo().StructLayoutAttribute.Size;
endian = endian ?? field.GetCustomAttribute<EndianAttribute>(false);
if (endian.Endianness == Endianness.Big && BitConverter.IsLittleEndian ||
endian.Endianness == Endianness.Little && !BitConverter.IsLittleEndian)
{
Array.Reverse(data, offset, length);
}
}
return data;
}
答案 0 :(得分:0)
您需要决定在运行时应使用哪种泛型类型。有一种方法可以做到:动态类型 C# Reference说,
动态类型使其发生的操作可以绕过编译时类型检查。相反,这些操作在运行时解决。
所以你可以定义一个方法:
static int GetLength<T>(T obj)
{
return Marshal.SizeOf<T>();
}
然后通过反射创建一个类型T
的实例作为动态:
dynamic obj = Activator.CreateInstance(field.FieldType.GetTypeInfo());
int length = GetLength(obj);
运行时将为方法选择合适的类型参数T.
此解决方案有一个限制,即您无法创建没有默认构造函数的类型的实例。您可以定义一个没有实际字段的包装类Wrapper<T>
,并将其创建为运行时,以确保构造函数正常工作。但我不知道它是否有效。