Добавление дополнительных атрибутов к каждому свойству класса - PullRequest
13 голосов
/ 30 ноября 2011

Скажем, у меня есть класс с любым количеством свойств любого типа

public class Test
{
public string A {get;set;}
public object B {get;set;}
public int C {get;set;}
public CustomClass D {get;set;}
}

Я хочу, чтобы все объекты в этом классе имели понятия «ошибки» и «предупреждения».Например, основываясь на каком-то условии в другом классе, я могу захотеть установить предупреждение для свойства A, а затем отобразить эту информацию в графическом интерфейсе.GUI не моя забота;скорее, как я должен установить это предупреждение?Я хотел бы иметь возможность сделать что-то вроде:

Для каждого свойства в классе, добавить свойство «Предупреждение» и «Ошибка», чтобы я мог сделать ..

Test t = new Test();
t.A.Warning = "This is a warning that the GUI will know to display in yellow".
t.B.Error = null;

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

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

Ответы [ 4 ]

9 голосов
/ 30 ноября 2011

Вы можете добавить в свойство пользовательский атрибут, а затем использовать метод расширения объекта для доступа к этим атрибутам.

Как-то так должно работать

Сначала вам нужно будет создать свой класс атрибута

[AttributeUsage(AttributeTargets.All/*, AllowMultiple = true*/)]
public class WarningAttribute : System.attribute
{
   public readonly string Warning;

   public WarningAttribute(string warning)
   {
      this.Warning = warning;
   }    
}

Больше чтения Здесь

Используйте это как таковое

[WarningAttribute("Warning String")]
public string A {get;set;}

Тогда получите к нему доступ, как это MSDN Article

public static string Warning(this Object object) 
{
    System.Attribute[] attrs = System.Attribute.GetCustomAttributes(object);

    foreach (System.Attribute attr in attrs)
        {
            if (attr is WarningAttrbiute)
            {
                return (WarningAttribute)attr.Warning;
            }
        } 
}

Тогда, если у вас есть предмет, к которому вы хотите получить доступ к предупреждению, вы можете просто позвонить

test.A.Warning;

Если вы хотите установить строку предупреждения, вы могли бы реализовать какой-то метод установки для этого немного более аккуратно. Потенциально путем установки вторичного объекта или типа свойства.


Альтернативный способ сделать это - вместо использования string и object вы можете создать собственный универсальный тип для обработки этого свойства.

что-то вроде

public class ValidationType<T>
{
   public T Value {get; set;}
   public string Warning {get; set;}
   public string Error {get; set;}

   public ValidationType(T value)
   {
      Value = value;
   }
}

Используйте как

var newWarning = new ValidationType<string>("Test Type");
newWarning.Warning = "Test STring";
Console.WriteLine("newWarning.Value");

2 голосов
/ 30 ноября 2011

Вместо того, чтобы пытаться приписать свойства, я бы предложил добавить коллекцию свойств ошибок / предупреждений в базовый класс, от которого наследуются ваши бизнес-объекты.

Таким образом, вы можете предоставить более подробную информацию, вы можете удалить их, когда они были отображены пользователю, и, если вы отправляете свои данные по «проводу» (веб-сервисы, сервисы wcf), ошибки может путешествовать с вашими объектами, не требуя специальной обработки для отправки атрибутов.

2 голосов
/ 30 ноября 2011

Если бы вы могли использовать метод вместо свойства, вы могли бы создать расширение для объекта - но тогда было бы трудно ограничить его использование только для некоторых классов.

Что-то вроде:

public static void Warning(this object target, string message)
{
...
}

public static String GetWarning(this object target)
{
}

Конечно, было бы трудно поддерживать такое предупреждение в состоянии объекта, но тогда вы могли бы использовать некоторые словари и т. Д.

1 голос
/ 30 ноября 2011

Во-первых, атрибуты не могут изменять объект, на котором они размещены.Если вы не объедините их с АОП.Я бы предложил использовать класс-оболочку вокруг класса, унаследовав его, если классы не запечатаны.Если они запечатаны, вам нужно будет написать реальный класс-обертку, передав все операции, кроме тех, которые вы добавили, в закрытое поле, которое является экземпляром класса, который вы упаковываете.

Редактировать:Для простоты использования предложенный метод расширения является, вероятно, лучшим решением.

...