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

时间:2016-07-21 15:35:46

标签: c# .net .net-core

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

1 个答案:

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