Вопрос

Я оказался в ситуации, когда использование класса 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...
}

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

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

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 в выражении (или разрешить произвольные лямбда-выражения и просто вставить номер строки или какой-либо другой общий текст.Я предлагаю не идти по этому пути, его использование уже сбивает с толку, а также может вызвать нежелательную нагрузку на то, что должно быть простым методом журналирования.

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

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

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

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

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();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top