2009-09-29 2 views
4

Возможно ли изменить атрибут свойства во время выполнения?Возможно ли изменить атрибут свойства во время выполнения?

скажем, у меня есть класс:

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

Есть ли способ сделать это?

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

Почему? Возможно, лучше установить значение для этого свойства, чтобы оно не делало то, что вы хотите. Или это для сериализации? –

+0

yep, для сериализации. – Natrium

+0

Правильно, так что вы пытаетесь сделать?Остановить заданное поле от сериализации? Или сделать его сериализованным на какой-то основе? Если это либо одно из них, вы всегда можете иметь два поля: один с «[NonSerialised]», который не сохраняется, и когда вы решите, что это нужно, вы устанавливаете «другое». Но нам понадобится немного больше информации о ваших точных рассуждениях для этого. –

ответ

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

Заметим, однако, что если вы используете этот второй подход вам нужно кэшировать экземпляр сериализатора, поскольку он испускает сборку каждый раз, когда вы делаете это. Я считаю, что первый подход проще ...

+0

Я говорю об атрибутах для включения/исключения некоторых свойств при сериализации. – Natrium

+0

поэтому, просто добавив свойство 'NameSpecified', xmlserializer знает, нужно ли ему сериализовать имя? Или я чего-то не хватает? – Natrium

5

Нет, это невозможно. Вы не можете изменять значения атрибутов из метаданных или метаданных в целом во время выполнения

Строго говоря, это не так. Существуют определенные API-интерфейсы, которые позволяют допускать некоторые генерации и модификации метаданных. Но они очень специфичны для сценариев (ENC, профилирование, отладка) и не должны использоваться в программах общего назначения.

1

Атрибуты запекаются в код во время компиляции. Единственный способ определения новых атрибутов во время выполнения - генерировать новый код во время выполнения (например, используя Reflection.Emit). Но вы не можете изменить атрибуты существующего кода.

1

Вы можете поместить переменную Boolean в класс, чтобы отключить/включить свойство, а не отключать его во время выполнения.

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); 
    } 
Смежные вопросы