我可以将自定义属性限制为仅无效方法吗?

Can I restrict a custom attribute to void methods only?

我有一个自定义属性,我想将其限制为 return 类型为 void 的方法。

我知道我可以限制使用 [AttributeUsage(AttributeTargets.Method)] 的方法,但似乎没有办法限制 return 类型或方法签名的任何其他方面。

[System.Diagnostics.Conditional] 属性正是我想要的那种限制。将其添加到非 void 方法会导致编译器错误:

The Conditional attribute is not valid on '(SomeMethod)' because its return type is not void

并且 IntelliSense 说:

Attribute 'System.Diagnostics.ConditionalAttribute' is only valid on attribute classes or methods with 'void' return type.

如果我 F12 到 ConditionalAttribute 我看到它装饰有以下属性:

[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
[ComVisible(true)]

None 其中提到了 return 类型。

Conditional 属性是如何完成的?我可以为我的自定义属性做同样的事情吗?

大多数属性只是附加到 classes 的元数据,可以在 运行 时检查。但是,编译器会使用一些属性。 System.ObsoleteAttribute 例如,如果使用 class 等方法,可用于让编译器发出错误或警告。 System.Diagnostics.ConditionalAttribute 是编译器使用的属性的另一个示例。因此,编译器本身可以自由地对其使用施加规则,这些规则不能应用于其他属性(例如仅限 void 方法)。

遗憾的是,目前无法通过自定义属性影响编译器。由于 Rosalyn 是用 C# 编写的,因此打开了将属性中的编译器 运行 代码作为编译阶段的一部分的方式。您将属性限制为 void 方法的示例将是此功能的一种此类用途,如果它已实现的话。

在我的特殊情况下,因为我使用的是 PostSharp,所以有一个解决方案。

我的自定义属性继承自 PostSharp.Aspects.MethodInterceptionAspect(继承自 Attribute),它具有可覆盖的 CompileTimeValidate(MethodBase method) 方法。

这允许在构建时发出编译器错误:

public override bool CompileTimeValidate(MethodBase method)
{
    Debug.Assert(method is MethodInfo);
    var methodInfo = (MethodInfo)method;

    if (methodInfo.ReturnType != typeof(void))
    {
        Message.Write(
            method, SeverityType.Error, "CX0001",
            "The Foo attribute is not valid on '{0}' because its return type is not void",
            method.Name);

        return false;
    }

    return true;
}