0

我让自己陷入了使用 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...
}

所以我的问题来了:检索这个属性的值不是不可能的,但它并不友好,因为我不得不使用一些反射。

我并不是真的害怕使用反射,但似乎我正在使用属性来处理它不是为它创建的东西。

我想知道使用属性的最佳位置在哪里,如果这真的是使用它的情况。

4

5 回答 5

4

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

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

于 2009-06-30T03:50:35.040 回答
1

你在正确的轨道上。

此外,已经为此目的定制了一个 [DisplayName] 属性,该属性自 2.0 以来一直存在于 .NET 中。

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

于 2009-06-30T04:21:39.310 回答
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

如果您希望这在运行时通过资源更具可配置性并且考虑到本地化,您可以这样做,但如果这是可能的要求,我会考虑另一种更标准化的方法。

PS,如果您想花哨,可以将 FieldInfo/PropertyInfo 开关替换为

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

然后您也可以在表达式中检查 MethodInfo (或允许任意 lambdas 并仅插入行号或其他一些通用文本。我建议不要沿着这条路线走,用法已经令人困惑,这也可能导致不需要的负载应该是一个简单的记录方法。

于 2009-06-30T11:43:33.183 回答
0

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

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

也许只是在你的对象中实现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();
}
于 2009-06-30T10:57:45.023 回答
0

这正是序列化的工作方式,所以我会说你的方法是合理的。解决此问题的另一种方法是创建 PropertyNames 及其标题的字典,然后根据属性名称查找标题。

于 2009-06-30T04:18:49.620 回答