Can I restrict a custom attribute to void methods only?
Asked Answered
R

2

9

I have a custom attribute which I would like to restrict to methods with return type void.

I know I can restrict to methods using [AttributeUsage(AttributeTargets.Method)] but there doesn't seem to be a way to restrict the return type or any other aspect of the methods signature.

The [System.Diagnostics.Conditional] attribute has exactly the kind of limitation I want. Adding it to a non-void method results in the compiler error:

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

and IntelliSense says:

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

If I F12 to the ConditionalAttribute I see that it is decorated with the following attributes:

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

None of which says anything about the return type.

How is it done for the Conditional attribute and can I do the same for my custom attribute?

Rooky answered 8/5, 2015 at 14:31 Comment(2)
You'll probably find this is more of a function of how its used rather than how its declared.Oona
As of now I don't think its possible, the System.Diagnostics.ConditionalAttribute source is unremarkable in that effect (dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/…). It must be some compiler magic. Rosalyn and C#6 may change that though.Nonpartisan
R
5

Turns out in my particular case there was a solution since I was using PostSharp.

My custom attribute inherits from PostSharp.Aspects.MethodInterceptionAspect (which inherits from Attribute) which has an overridable CompileTimeValidate(MethodBase method) method.

This allows to emit compiler errors during build time:

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;
}
Rooky answered 11/5, 2015 at 7:39 Comment(0)
A
3

Most attributes are simply metadata that gets attached to classes and that can be examined at runtime. However, some attributes are used by the compiler. System.ObsoleteAttribute for example can be used to have the compiler emit errors or warnings if the method, class etc is used. System.Diagnostics.ConditionalAttribute is another example of an attribute used by the compiler. As such, the compiler itself is free to impose rules on its use that cannot be applied to other attributes (such as void methods only).

Unfortunately, at this time, it's not possible to affect the compiler though custom attributes. With Rosalyn being written in C#, the way is then opened up to have the compiler run code within the attribute as part of the compilation phase. Your example of restriction an attribute to void methods would be one such use of this feature, if it were implemented.

Amytal answered 8/5, 2015 at 15:6 Comment(1)
Thanks for your answer! I would have accepted it but I actually found a solution using postsharp (which I was using anyway). See my own answer for details.Rooky

© 2022 - 2024 — McMap. All rights reserved.