【问题标题】:Passing a type as parameter to an attribute将类型作为参数传递给属性
【发布时间】:2011-08-15 08:40:32
【问题描述】:

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

为了保持简洁和易于更改,我创建了一个扩展 AttributeField 类,使用 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) 将从文件中提取数据,在适当的偏移处读取适当的类型和大小。

但是,我发现将类型名称作为字符串传递是丑陋的。

是否可以以更优雅、更简短的方式传递 type,以及如何传递?

谢谢。

【问题讨论】:

  • 类型和标记的字段一样,不是吗?为什么不从字段中获取类型,而不是在属性的构造函数中标记它?

标签: c# generics custom-attributes


【解决方案1】:

在 C# 10 中,有一个 new feature(在本文发布时处于预览状态)允许您创建通用属性!

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

public class GenericAttribute<T> : Attribute { }

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

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

【讨论】:

    【解决方案2】:

    我认为你不需要把类型放在属性的构造函数中,你可以从字段中获取。看例子:

    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
            }
        }
    }
    

    【讨论】:

    • @Heandel:也许我误解了你的想法。但事实是,一个属性无法获取其“衣架”的信息。换句话说,您有一个名为a 的属性的实例,您无法分辨a 正在标记哪个字段/属性/类。
    【解决方案3】:

    是的,参数必须是Type类型,然后你可以按如下传递类型:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

        • @Heandel:在每个属性中键入安全和重构支持,而在每个属性中添加六个额外字符 == 我会皱眉头 :-)
        • @Heandel,这是唯一干净的方法......它有点长,但比使用字符串好 100 倍
        • 我只是将 typeof 的真棒除以 string 的真棒......正如你所看到的,这是一个非常准确的估计;)
        猜你喜欢
        • 2021-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多