如何从.NET Core中的类型中获取特定属性的封送大小

本文关键字:属性 类型 NET Core 获取 | 更新日期: 2023-09-27 17:58:01

在.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;
}

如何从.NET Core中的类型中获取特定属性的封送大小

您需要的是决定在运行时应该使用什么泛型类型。确实有一种方法可以做到这一点:动态类型
C#参考说,

动态类型使其发生的操作能够绕过编译时类型检查。相反,这些操作在运行时解决。

所以你可以定义一个方法:

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>,并将其创建为运行时,以确保构造函数能够工作。但我不知道它是否有效。