使用System.Attribute类

时间:2009-06-30 03:43:33

标签: c# reflection code-reuse

我自己处于这样一种情况:使用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 个答案:

答案 0 :(得分:4)

属性和反思齐头并进。除了一些编译器/运行时属性之外,没有办法使用它们而不反映代码。

那就是说,你的方法是合理的,你可能想看一下System.ComponentModel命名空间中的属性,这些属性有许多类来用有用的元数据来装饰属性。

答案 1 :(得分:1)

你走在正确的轨道上。

此外,还有一个[DisplayName]属性已经为此目的量身定制,从2.0开始就在.NET中。

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

答案 2 :(得分:1)

如果您只是写入控制台,即它的调试样式输出,那么您想要的是错误/复制粘贴错误的可能性很小。

这引起了人们的困惑,但在呼叫站点非常有效:

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(或允许任意lambdas,只需插入行号或其他一些通用文本。我建议不要沿着这条路线走,这种用法已经混淆了这也可能导致不必要的加载应该是一个简单的日志记录方法。

答案 3 :(得分:0)

这正是Serialization的工作方式,所以我想说你的方法是合理的。另一种方法是创建一个PropertyNames字典及其标题,然后根据属性名称查找标题。

答案 4 :(得分:0)

  
    

我的应用程序中有一个要打印的对象,我需要在每个属性之前添加一个标签(或者只是前面的一个字符串)。

  

为什么你会想到在你的情况下使用属性?在应用程序中何处打印此对象。

也许只是在你的对象中实现 ToString
E.g。

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();
}