是否可以在运行时修改属性的属性?

时间:2009-09-29 06:14:55

标签: c# attributes

是否可以在运行时修改属性的属性?

让我说我有一些课程:

public class TheClass
{
    [TheAttribute]
    public int TheProperty { get; set; }
}

有办法做到这一点吗?

if (someCondition)
{
    // disable attribute. Is this possible and how can this be done?
}

7 个答案:

答案 0 :(得分:5)

不,这是不可能的。您无法在运行时从元数据或一般元数据修改属性值

严格来说,上述情况并非如此。某些API允许允许一些元数据生成和修改。但它们非常特定于场景(ENC,分析,调试),不应用于通用程序。

答案 1 :(得分:2)

取决于;从反思的角度来看:没有。你不能。但是,如果您在谈论System.ComponentModel在数据绑定等事物中使用的属性,则可以使用TypeDescriptor.AddAttributes附加额外的属性。或涉及自定义描述符的其他客户模型。所以这取决于用例。


在xml序列化的情况下,它变得更有趣。首先,我们可以使用有趣的对象模型:

using System;
using System.Xml.Serialization;
public class MyData
{
    [XmlAttribute]
    public int Id { get; set; }
    [XmlAttribute]
    public string Name { get; set; }
    [XmlIgnore]
    public bool NameSpecified { get; set; }

    static void Main()
    {
        var ser = new XmlSerializer(typeof(MyData));

        var obj1 = new MyData { Id = 1, Name = "Fred", NameSpecified = true };
        ser.Serialize(Console.Out, obj1);
        Console.WriteLine();
        Console.WriteLine();
        var obj2 = new MyData { Id = 2, Name = "Fred", NameSpecified = false };
        ser.Serialize(Console.Out, obj2);
    }
}

bool {name}Specified {get;set;}模式(以及bool ShouldSerialize{name}())被识别并用于控制要包含的元素。

另一种选择是使用非默认的ctor:

using System;
using System.Xml.Serialization;
public class MyData
{
    [XmlAttribute]
    public int Id { get; set; }
    public string Name { get; set; }

    static void Main()
    {
        var obj = new MyData { Id = 1, Name = "Fred" };

        XmlAttributeOverrides config1 = new XmlAttributeOverrides();
        config1.Add(typeof(MyData),"Name",
            new XmlAttributes { XmlIgnore = true});
        var ser1 = new XmlSerializer(typeof(MyData),config1); 
        ser1.Serialize(Console.Out, obj);
        Console.WriteLine();
        Console.WriteLine();
        XmlAttributeOverrides config2 = new XmlAttributeOverrides();
        config2.Add(typeof(MyData), "Name",
            new XmlAttributes { XmlIgnore = false });
        var ser2 = new XmlSerializer(typeof(MyData), config2);
        ser2.Serialize(Console.Out, obj);
    }
}

请注意,如果使用第二种方法,则需要缓存序列化程序实例,因为每次执行此操作时都会发出程序集。我发现第一种方法更简单......

答案 2 :(得分:1)

属性在编译时被烘焙到代码中。在运行时定义新属性的唯一方法是在运行时生成新代码(例如,使用Reflection.Emit)。但是你不能改变现有代码的属性。

答案 3 :(得分:1)

您可以在类中放置Boolean变量来禁用/启用该属性,而不是在运行时禁用它。

答案 4 :(得分:1)

答案 5 :(得分:0)

听起来您想考虑实施IXmlSerializable

答案 6 :(得分:0)

您可以实现IDataErrorInfo,然后在Validate方法中检查范围。

    public string this[string property] {
        get { return Validate(property); }
    }

    public string Error { get; }

    protected virtual string Validate(string property) {
        var propertyInfo = this.GetType().GetProperty(property);
        var results = new List<ValidationResult>();

        var result = Validator.TryValidateProperty(
                                  propertyInfo.GetValue(this, null),
                                  new ValidationContext(this, null, null) {
                                      MemberName = property
                                  },
                                  results);

        if (!result) {
            var validationResult = results.First();
            return validationResult.ErrorMessage;
        }

        return string.Empty;
    }

在子类

protected override string Validate(string property) {
        Debug.WriteLine(property);
        if (property == nameof(YourProperty)) {
            if (_property > 5) {
                return "_property out of range";
            }
        }
        return base.Validate(property);
    }