如何使用属性向 C# 类添加可见信息?

发布于 2025-01-01 09:12:52 字数 1087 浏览 0 评论 0原文

我正在尝试向 C# 界面添加信息,并且我正在尝试使用属性添加此信息。

举例来说,我到处都有 int 参数,其中一些 int 参数是“行 ID”,一些是“列 ID”。我希望能够做到这一点:

namespace RowIdTest1
{
    using System;

    public class Class1
    {
        public int Get([RowId] int r, [ColumnId] int c) { return 3; }
        public void Set([RowId] int r, [ColumnId] int c, int x) { return; }
    }

    [AttributeUsageAttribute(AttributeTargets.All)]
    public class RowIdAttribute : System.Attribute { }

    [AttributeUsageAttribute(AttributeTargets.All)]
    public class ColumnIdAttribute : System.Attribute { }
}

这样当另一个程序员使用我的 DLL 并在 Visual Studio 中浏览到 Class1 时, 他或她会在“Class1(来自元数据)”窗口中看到这一点:

namespace RowIdTest1
{
    public class Class1
    {
        public Class1();

        public int Get([RowId] int r, [ColumnID] int c);
        public void Set([RowId] int r, [ColumnID] int c, int x);
    }
}

当我尝试时,属性根本不会出现。

我知道你可以用 ///- 注释来做这种事情。

我知道您可以在任何内容上使用 System.ComponentModel.DescriptionAttribute 类(尽管会出现方法的描述,但不会出现参数的描述)。

我是否对 C# 属性做了一些完全奇怪的事情?不当?疯狂的?

I am trying to add information to a C# interface, and I am trying to add this information using attributes.

Say for example, that I have int parameters everywhere, and some of these int parameters are "row IDs" and some are "column IDs". I'd like to be able to do this:

namespace RowIdTest1
{
    using System;

    public class Class1
    {
        public int Get([RowId] int r, [ColumnId] int c) { return 3; }
        public void Set([RowId] int r, [ColumnId] int c, int x) { return; }
    }

    [AttributeUsageAttribute(AttributeTargets.All)]
    public class RowIdAttribute : System.Attribute { }

    [AttributeUsageAttribute(AttributeTargets.All)]
    public class ColumnIdAttribute : System.Attribute { }
}

so that when another programmer uses my DLL and browses to Class1 in Visual Studio,
he or she would see this in the "Class1 (from metadata)" window:

namespace RowIdTest1
{
    public class Class1
    {
        public Class1();

        public int Get([RowId] int r, [ColumnID] int c);
        public void Set([RowId] int r, [ColumnID] int c, int x);
    }
}

When I try it, the attributes don't appear at all.

I know you can do this sort of thing with ///-comments.

I know that you can use the System.ComponentModel.DescriptionAttribute class on anything (although descriptions on methods will appear but descriptions on parameters will not appear).

Am I doing something totally weird with C# attributes? Inappropriate? Insane?

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

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

发布评论

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

评论(5

并安 2025-01-08 09:12:52

我是否使用 C# 属性做了一些完全奇怪的事情?

是的。

您正在尝试使用属性来表达有关参数的业务领域事实。这不是属性的用途。属性用于表达有关编程语言机制的事实。也就是说,当您说:

[Obsolete]
class BlackAndWhiteTelevision {}

这就是说类本身已过时,您不应再使用它,因为已被不同的类替换。不要使用过时的属性来声明该类所代表的物理世界事物不能再制造和销售以获取利润。

特定参数代表行标识符是关于方法的业务的事实,而不是关于方法的机制。您应该在方法参数上添加属性,以表达“此参数有默认值”或“通过 COM 互操作调用时应按值编组此参数”或“此参数将在读取之前写入” -- 这些是关于参数作为编程语言中的变量的事实,而不是关于参数如何对业务流程中的某些概念进行建模的事实。

有关如何使用属性来表达有关机制而不是业务领域的事实的更多想法,请参阅我关于该主题的文章及其评论:

http://blogs.msdn.com/b/ericlippert/archive/2009/02/02/properties-vs-attributes.aspx

Am I doing something totally weird with C# attributes?

Yes.

You are trying to use an attribute to express a business domain fact about the parameter. That's not what attributes are for. Attributes are for expressing facts about the programming language mechanism. That is, when you say:

[Obsolete]
class BlackAndWhiteTelevision {}

That is saying that the class itself is obsolete and that you should no longer use it because the class has been replaced with a different class. Do not use the obsolete attribute to state that the physical world thing that the class represents can no longer be manufactured and sold at a profit.

That a particular parameter represents a row identifier is a fact about the business of your method, not about the mechanism of the method. You should put attributes on method parameters that express things like "this parameter has a default value" or "this parameter should be marshalled by value when called via COM interop" or "this parameter is going to be written to before it is read from" -- those are facts about the parameter as a variable in a programming language, rather than facts about how the parameter models some concept in your business process.

For more thoughts on how to use attributes to express facts about mechanisms instead of business domains, see my article on the subject and the comments to it:

http://blogs.msdn.com/b/ericlippert/archive/2009/02/02/properties-vs-attributes.aspx

离线来电— 2025-01-08 09:12:52

我是否对 C# 属性做了一些完全奇怪的事情?不当?疯了吗?

一般来说,使用属性的原因是因为您希望在运行时通过反射让程序获得有关类或其成员的某些信息。这与这个想法不符,所以我认为这是对属性的不恰当使用。

我认为给程序员一个微妙的提示,即您希望参数代表 rowId 的更优选方法是使用参数名称:

public int Get(int rowId, int columnId)

将其与 /// 注释结合起来,就像您提到的那样,您有一个非常有效的方法来告诉您所在阶层的消费者您的期望是什么。

最后,如果您确实想防止用户意外地以错误的顺序提供参数,您可以利用强类型。

public struct RowId {
    private int _rowId;
    public int Value{get{return _rowId;}}
    public RowId(int rowId) {_rowId = rowId;}
}


public int Get(RowId rowId, ColumnId columnId)

这使得某人几乎不可能意外地混淆输入。 (请注意,我并不推荐这种模式:它带来了大量的开销,但带来的好处却很少。)

Am I doing something totally weird with C# attributes? Inappropriate? Insane?

In general, the reason to use attributes is because you want to have certain information about a class or its members available to your program via reflection at runtime. This isn't in keeping with that idea, so I'd say it's an inappropriate use of attributes.

I think a more preferred way to give the programmer a subtle hint that you want the parameter to represent a rowId is to use the parameter name:

public int Get(int rowId, int columnId)

Couple this with /// comments, like you mention, and you have a pretty effective way to tell consumers of your class what your expectations are.

Finally, if you really want to prevent users from accidentally providing the arguments in the wrong order, you could leverage strong typing.

public struct RowId {
    private int _rowId;
    public int Value{get{return _rowId;}}
    public RowId(int rowId) {_rowId = rowId;}
}


public int Get(RowId rowId, ColumnId columnId)

This would make it nearly impossible for someone to accidentally mix up the inputs. (Note that I am not recommending this pattern: It introduces a lot of overhead for very little benefit.)

月朦胧 2025-01-08 09:12:52

不,你不能。为什么不直接说出参数的名称呢

public int Get(int rowId, int columnId)

No, you can't. Why not just name the arguments

public int Get(int rowId, int columnId)

?

落花随流水 2025-01-08 09:12:52

我不得不说我不太明白这一点。您的库的用户(我假设)必须反编译您的类才能查看元数据,这是否很常见?为什么不直接为接口编写一些 XML 文档并将其与您的库一起提供呢?

I have to say I don't understand this very well. Is it common that users of your library (I assume) have to decompile your classes to look at the metadata? Why not just write some XML documentation for the interface and ship it with your library instead?

三生路 2025-01-08 09:12:52

不知道这算不算“疯狂”。如果它不能按原样工作,也许可以将属性分配给某种数据结构内的嵌套项,然后可以将数据结构作为参数传递给函数。只是一个想法。

I don't know if it's "insane". If it isn't working as is, maybe, assign the attributes to nested items inside of some kind of data structure, and then maybe pass the data structure as a parameter to the function. Just one idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文