Могу ли я ограничить настраиваемый атрибут только недействительными методами?

У меня есть настраиваемый атрибут, который я хотел бы ограничить методами с возвращаемым типом void.

Я знаю, что могу ограничить методы, использующие [AttributeUsage(AttributeTargets.Method)], но, похоже, нет способа ограничить тип возвращаемого значения или любой другой аспект сигнатуры методов.

Атрибут [System.Diagnostics.Conditional] имеет именно то ограничение, которое мне нужно. Добавление его к непустому методу приводит к ошибке компилятора:

Атрибут Conditional недействителен для '(SomeMethod)', поскольку его возвращаемый тип не является недействительным

и IntelliSense говорит:

Атрибут System.Diagnostics.ConditionalAttribute действителен только для классов атрибутов или методов с возвращаемым типом void.

Если я F12 на ConditionalAttribute, я вижу, что он украшен следующими атрибутами:

[Сериализуемый]
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
[ComVisible (true)]

Ничего из этого не говорит о возвращаемом типе.

Как это делается для атрибута Conditional и могу ли я сделать то же самое для своего настраиваемого атрибута?


person Roman Reiner    schedule 08.05.2015    source источник
comment
Вы, вероятно, обнаружите, что это больше зависит от того, как его используется, а не от того, как его объявлено.   -  person Jamiec    schedule 08.05.2015
comment
На данный момент я не думаю, что это возможно, источник System.Diagnostics.ConditionalAttribute ничем не примечателен в этом отношении (dotnetframework.org/default.aspx/4@0/4@0/ DEVDIV_TFS / Dev10 /). Должно быть, это какая-то магия компилятора. Однако Розалин и C # 6 могут это изменить.   -  person Ron Beyer    schedule 08.05.2015


Ответы (2)


Оказывается, в моем конкретном случае решение было, так как я использовал 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;
}
person Roman Reiner    schedule 11.05.2015

Большинство атрибутов - это просто метаданные, которые прикрепляются к классам и могут быть проверены во время выполнения. Однако некоторые атрибуты используются компилятором. System.ObsoleteAttribute, например, можно использовать, чтобы компилятор выдавал ошибки или предупреждения, если используется метод, класс и т. Д. System.Diagnostics.ConditionalAttribute - еще один пример атрибута, используемого компилятором. Таким образом, сам компилятор может устанавливать правила своего использования, которые не могут применяться к другим атрибутам (например, только к методам void).

К сожалению, в настоящее время невозможно повлиять на компилятор с помощью настраиваемых атрибутов. Когда Rosalyn пишется на C #, появляется возможность заставить компилятор запускать код внутри атрибута как часть фазы компиляции. Ваш пример ограничения атрибута для методов void был бы одним из таких вариантов использования этой функции, если бы она была реализована.

person David Arno    schedule 08.05.2015
comment
Спасибо за Ваш ответ! Я бы принял это, но на самом деле я нашел решение с помощью postharp (который я все равно использовал). Подробности см. В моем собственном ответе. - person Roman Reiner; 11.05.2015