使用 System.Attribute 类

发布于 2024-07-25 08:08:29 字数 658 浏览 10 评论 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...
}

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

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

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

I got myself in a situation where using the System.Attribute class seemed (at first glance) to be a good idea.

I have an object to be printed in my application, and I need a label before each property (or just a string before it). I could put each property hardcoded like:

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

And so on for each property. But instead of it, I was trying to create a code where this 'label' doesn't needed to be hardcoded, so I could print every property dynamically.

I got something like that, using System.Attribute class:

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

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

So here comes my problem: retrieving this Attribute's value is not impossible, but it's not friendly since I had to use some reflection for it.

I'm not really scared of using reflection, but it seemed that I was using attributes for something that it wasn't created for.

I wonder where are the best places for using attributes, and if this is really a situation for using it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

剪不断理还乱 2024-08-01 08:08:29

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

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

Attributes and reflection go hand in hand. With the exception of some compiler/runtime attributes, there's no way to use them with out reflecting over the code.

That said, your approach is reasonable, and you might want to take a look at the attributes in the System.ComponentModel namespace which have a number of classes to decorate properties with useful metadata.

爱本泡沫多脆弱 2024-08-01 08:08:29

你走在正确的轨道上。

此外,还有一个为此目的量身定制的 [DisplayName] 属性,该属性自 2.0 起就已存在于 .NET 中。

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

You're on the right track.

Also, there is a [DisplayName] attribute already tailor-made for this purpose, which has been in .NET since 2.0.

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

财迷小姐 2024-08-01 08:08:29

如果您只是写入控制台,即它是调试样式输出,那么您想要的就是将拼写错误/复制粘贴错误的可能性降到最低。

这在幕后令人困惑,但在调用站点非常有效:

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 (或者允许任意 lambda 并只插入行号或一些其他通用文本。我建议不要继续下去这条路线的用法已经很混乱,这也可能会在本应是简单的日志记录方法中造成不必要的负载。

If you're just writing to the console, i.e. it's debugging style output then what you want is minimal chance of typo/copy paste error.

This is confusing under the hood but is highly effective at the call sites:

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

then you can write

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

If you want this to be more configurable at runtime via resources and with considerations for localization you can do so but I would consider another, more standardized, approach instead if this was a likely requirement.

P.S. if you wanted to get fancy you could replace the FieldInfo/PropertyInfo switch with

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

and then you could check for MethodInfo in the expression as well (or allow arbitrary lambdas and just insert the line number or some other generic text. I suggest not going down this route, the usage is already confusing also this may cause unwanted load in what should be a simple logging method.

撩人痒 2024-08-01 08:08:29

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

this is exactly how Serialization works so I would say your approach is reasonable. Another way you can approach this is to create a dictionary of PropertyNames and their Titles and then look up the title based on the property name.

忱杏 2024-08-01 08:08:29

<块引用>

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

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

也许只需在您的对象中实现 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();
}

I have an object to be printed in my application, and I need a label before each property (or just a string before it).

Why do you think of using attributes in your case? Where do you print this objects in your application.

Maybe just implement ToString in your object(s)
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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文