Добавление дополнительных атрибутов к каждому свойству класса
Скажем, у меня есть класс с любым количеством свойств любого типа
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 не беспокоит меня; скорее, как мне установить это предупреждение? Я хотел бы иметь возможность сделать что-то вроде:
Для каждого свойства в классе добавьте свойство "Warning" и "Error", которое я могу сделать.
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), а затем передают строки, соответствующие именам свойств, или используют отражение, чтобы получить имя свойства и передать его, но я бы предпочел что-то более чистое.
Ответы
Ответ 1
Вы можете добавить настраиваемый атрибут, который вы хотите для свойства, а затем использовать метод расширения для объекта для доступа к этим атрибутам.
Что-то вроде этого должно работать
Сначала вам нужно создать свой класс атрибутов
[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");
Ответ 2
Если вам удастся избежать метода вместо свойства, то вы можете создать расширение для объекта, но тогда было бы трудно сузить его, используя только для некоторых классов.
Что-то вроде:
public static void Warning(this object target, string message)
{
...
}
public static String GetWarning(this object target)
{
}
Конечно, было бы сложно поддерживать такое предупреждение в состоянии объекта, но тогда вы могли бы использовать некоторые словари и т.д.
Ответ 3
Вместо того, чтобы пытаться атрибутировать свойства, я бы предложил добавить набор свойств ошибки/предупреждения в базовый класс, который наследует ваши бизнес-объекты.
Таким образом, вы можете предоставить более подробную информацию, вы можете удалить их, когда они были показаны пользователю, и, если вы отправляете свои данные по "проводнику" (веб-сервисам, службам wcf), ошибки может перемещаться с вашими объектами, а не требовать специальной обработки для отправки атрибутов.
Ответ 4
Во-первых, атрибуты не могут изменять объект, на который они были помещены. Если вы не объедините их с АОП. Я бы предложил использовать класс оболочки вокруг класса, наследуя его, если классы не запечатаны. Если они запечатаны, вам придется написать фактический класс-оболочку, передав все операции, кроме тех, которые вы добавляете, в частное поле, которое является экземпляром класса, который вы обертываете.
Изменить:
Для удобства использования предложенный выше метод расширения, вероятно, является лучшим решением.