Использование класса System.Attribute - PullRequest
0 голосов
/ 30 июня 2009

Я попал в ситуацию, когда использование класса System.Attribute показалось (на первый взгляд) хорошей идеей.

У меня есть объект для печати в моем приложении, и мне нужна метка перед каждым свойством (или просто строка перед ним). Я мог бы указать каждое свойство как:

Console.WriteLine("Color:"+obj.color);
Console.WriteLine("Size:"+obj.size);

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

Я получил что-то подобное, используя класс System.Attribute:

public class MyObject 
{
    [MyCustomLabel("Color:")]
    public string Color;

    [MyCustomLabel("Size:")]
    public string Size;
    //etc...
}

Итак, вот моя проблема: получение значения этого атрибута не является невозможным, но это не очень удобно, поскольку мне пришлось использовать какое-то отражение для него.

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

Интересно, где находятся лучшие места для использования атрибутов, и действительно ли это ситуация для их использования?

Ответы [ 5 ]

4 голосов
/ 30 июня 2009

Атрибуты и рефлексия идут рука об руку. За исключением некоторых атрибутов компилятора / среды выполнения, их невозможно использовать без отражения в коде.

Тем не менее, ваш подход разумен, и вы можете взглянуть на атрибуты в пространстве имен System.ComponentModel, которые имеют ряд классов для украшения свойств полезными метаданными.

1 голос
/ 30 июня 2009

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

Это сбивает с толку под капотом, но очень эффективно на сайтах вызовов:

public static void WriteNameAndValue<T,TValue>(
    this TextWriter tw, T t,
    Expression<Func<T, TValue>> getter)
{
    var memberExpression = getter.Body as MemberExpression;
    if (memberExpression == null)
        throw new ArgumentException("missing body!");
    var member = memberExpression.Member;
    tw.Write(member.Name);
    tw.Write(": ");
    if (member is FieldInfo)
    {
        tw.Write(((FieldInfo)member).GetValue(t));
    }
    else if (member is PropertyInfo)
    {
        tw.Write(((PropertyInfo)member).GetValue(t, null));
    }
}


public static void WriteNameAndValueLine<T,TValue>(
    this TextWriter tw, T t,
    Expression<Func<T, TValue>> getter)
{

    WriteNameAndValue<T,TValue>(tw, t, getter);
    tw.WriteLine();
}

тогда вы можете написать

t.Foo = "bar";
t.Bar = 32.5;
Console.Out.WriteNameAndValueLine(t, x => x.Foo);
Console.Out.WriteNameAndValueLine(t, x => x.Bar);
// output
// Foo: bar
// Bar: 32.5

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

P.S. если вы хотите получить фантазию, вы можете заменить переключатель FieldInfo / PropertyInfo на

tw.Write(getter.Compile()(t));

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

1 голос
/ 30 июня 2009

Вы на правильном пути.

Кроме того, существует атрибут [DisplayName], уже созданный специально для этой цели, который используется в .NET с 2.0.

http://msdn.microsoft.com/en-us/library/system.componentmodel.displaynameattribute.aspx

0 голосов
/ 30 июня 2009

У меня есть объект для печати в моем приложении, и мне нужна метка перед каждым свойством (или просто строка перед ним).

Почему вы думаете об использовании атрибутов в вашем случае? Где вы печатаете эти объекты в вашем приложении.

Может быть, просто реализовать ToString в вашем объекте (ах)
Э.Г.

public override string ToString()
{
    StringBuilder sb = new StringBuilder();

    sb.Append("PropertyX: ");
    sb.AppendLine(this.PropertyX);

    // get string from resource file
    sb.Append(Resources.FileName);
    sb.Append(": ");
    sb.AppendLine(this.FileName);

    sb.Append("Number: ");
    sb.AppendLine(this.Number.ToString());

    return sb.ToString();
}
0 голосов
/ 30 июня 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...