Добавление дополнительных атрибутов к каждому свойству класса

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

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

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

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

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

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

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


person user981225    schedule 30.11.2011    source источник


Ответы (4)


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

Что-то вроде этого должно работать

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

[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

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

person msarchet    schedule 30.11.2011
comment
Благодарю за ваш ответ. Думаю реализовать это. Мне не нравится использовать newWarning.Value для фактического доступа к свойствам строки, но, похоже, мне придется где-то пожертвовать некоторым удобством. - person user981225; 01.12.2011

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

Что-то типа:

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

public static String GetWarning(this object target)
{
}

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

person Piotr Zierhoffer    schedule 30.11.2011
comment
Спасибо за ваш пост, но я бы предпочел избежать этого решения. Я хочу, чтобы фактическое свойство знало, есть ли у него ошибка, а не для того, чтобы родительский объект перебирал словарь строк (например). - person user981225; 01.12.2011

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

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

person competent_tech    schedule 30.11.2011

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

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

person Orvid King    schedule 30.11.2011