将类型作为参数传递给属性

本文关键字:属性 参数传递 类型 | 更新日期: 2023-09-27 17:53:34

我编写了一个有点通用的反序列化机制,它允许我从c++应用程序使用的二进制文件格式构造对象。

为了保持简洁和易于更改,我创建了一个Field类,它扩展了Attribute,由Field(int offset, string type, int length, int padding)构造,并应用于我希望反序列化的类属性。它看起来是这样的:

[Field(0x04, "int")]
public int ID = 0;
[Field(0x08, "string", 0x48)]
public string Name = "0";
[Field(0x6C, "byte", 3)]
public byte[] Color = { 0, 0, 0 };
[Field(0x70, "int")]
public int BackgroundSoundEffect = 0;
[Field(0x74, "byte", 3)]
public byte[] BackgroundColor = { 0, 0, 0 };
[Field(0x78, "byte", 3)]
public byte[] BackgroundLightPower = { 0, 0, 0 };
[Field(0x7C, "float", 3)]
public float[] BackgroundLightAngle = { 0.0f, 0.0f, 0.0f };

调用myClass.Decompile(pathToBinaryFile)将从文件中提取数据,在适当的偏移量读取适当的类型和大小。

但是,我发现将类型名作为字符串传递是很难看的。

是否可以用更简洁的方式传递类型,如何传递?

谢谢。

将类型作为参数传递给属性

使用typeof运算符(返回Type的一个实例):

[Field(0x7C, typeof(float), 3)]

是:使属性以Type作为参数,然后传递例如typeof(int)

是的,参数的类型必须是Type,然后您可以像下面这样传递类型:

[Field(0x7C, typeof(float), 3)]
public float[] BackgroundLightAngle = { 0.0f, 0.0f, 0.0f };

我认为您不需要将类型放在属性的构造函数中,您可以从字段中获取它。参见示例:

public class FieldAttribute : Attribute { }
class Data
{
    [Field]
    public int Num;
    [Field]
    public string Name;
    public decimal NonField;
}

class Deserializer
{
    public static void Deserialize(object data)
    {
        var fields = data.GetType().GetFields();
        foreach (var field in fields)
        {
            Type t = field.FieldType;
            FieldAttribute attr = field.GetCustomAttributes(false)
                                     .Where(x => x is FieldAttribute)
                                     .FirstOrDefault() as FieldAttribute;
            if (attr == null) return;
            //now you have the type and the attribute
            //and even the field with its value
        }
    }
}

在c# 10中有一个新特性(在本文发布时还处于预览阶段),允许您创建通用属性!

使用这个新特性,您可以创建一个通用属性:

public class GenericAttribute<T> : Attribute { }

然后,指定使用属性的类型参数:

[GenericAttribute<string>()]
public string Method() => default;