C#属性命名

Bug*_*eeb 2 c#

C# 编译器是否识别继承的属性类以检查它们是否包含“属性”一词?在下面的示例中,[Blah]、[BlahA] 和 [BlahAttribute] 是可用属性

    [AttributeUsage(AttributeTargets.Method, AllowMultiple=true)]
    public class BlahA: Attribute
    {
        //stuff
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple=true)]
    public class BlahAttribute: Attribute
    {
        //stuff
    }

    //acceptable
    [BlahA]
    [Blah]
    [BlahAttribute]
Run Code Online (Sandbox Code Playgroud)

V0l*_*dek 5

规范对此相当清楚:

从抽象类 System.Attribute 派生的类,无论是直接还是间接,都是属性类。属性类的声明定义了一种可以放置在声明上的新属性。按照惯例,属性类以 Attribute 后缀命名。属性的使用可以包含或省略此后缀。

在属性规范下进一步向下:

按照惯例,属性类的命名后缀为Attribute. 形式为type_nameattribute_name可以包含或省略此后缀。如果发现有和没有此后缀的属性类,则存在歧义,并导致编译时错误。如果attribute_name的拼写使得其最右侧的标识符是逐字标识符 (...),则仅匹配没有后缀的属性,从而能够解决这种歧义。

来源

由于规范允许用户包含或省略此后缀,因此 C# 编译器也允许两者。在你的情况下,[BlahA]指的是BlahA,而[Blah][BlahAttribute]BlahAttribute。如果你定义的名称属性Blah[Blah]将是不明确的,你必须通过指定解决它[BlahAttribute]或使用逐字标识符[@Blah]

更新:

我潜伏在 Roslyn 的源代码中,完全是偶然发现了负责规范这一部分的部分。您可以在Microsoft.CodeAnalysis.CSharp.Binder.Binder_Lookup(至少截至 2020 年 5 月 19 日)中找到它们。碰巧在那里描述了一个相当有趣的边缘情况。当解析属性的类型时,它们会查找FooFooAttribute如上所述。如果其中只有一个是可行的,则他们选择那个,如果两者都是,则报告歧义。但是,如果其中一个是可行的,而另一个本身不明确,他们就会慷慨地选择单一可行的选项。为了说明这一点,请考虑:

namespace A
{
    class FooAttribute : System.Attribute
    {

    }
}

namespace B
{
    class FooAttribute : System.Attribute
    {
    }
}

namespace C
{
    class Foo : System.Attribute
    {
    }
}

namespace D
{
    using A;
    using B;
    using C;

    [Foo] // Attribute resolution.
    class Bar 
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

属性解析的候选对象是A.FooAttributeB.FooAttribute使用Attribute后缀C.Foo查看时以及不使用后缀查看时。第一个选择是不明确的 - 编译器无法在A's 和B's 版本之间做出决定- 所以C.Foo选择了上面的代码并编译。现在删除using Aorusing B指令中的任何一个。突然间,只有一个FooAttribute是可行的候选者,并且它和 之间存在歧义C.Foo试试吧