Подтвердить что ты не робот

Аргумент атрибута должен быть постоянной ошибкой при использовании необязательного параметра в конструкторе атрибутов

Может ли кто-нибудь объяснить, почему работает этот код:

public class AdministratorSettingValidationAttribute : Attribute
{
    public AdministratorSettingValidationAttribute(AdministratorSettingDataType administratorSettingDataType)
    {
        DataType = administratorSettingDataType;
    }

    public AdministratorSettingValidationAttribute(AdministratorSettingDataType administratorSettingDataType, Type enumerationType)
    {
        DataType = administratorSettingDataType;
        EnumerationType = enumerationType;
    }
}

... но рефакторинг для использования необязательного параметра:

    public AdministratorSettingValidationAttribute(AdministratorSettingDataType administratorSettingDataType, Type enumerationType = null)
    {
        DataType = administratorSettingDataType;
        EnumerationType = enumerationType;
    }

... вызывает ошибку времени компиляции: " Аргумент атрибута должен быть константным выражением, выражением типа или выражением выражения массива типа параметра атрибута".

4b9b3361

Ответ 1

UPDATE

Ошибка была зарегистрирована в июле прошлого года и уже исправлена. Исправление появится в следующей версии С#. Подробнее см. В этой статье:

http://connect.microsoft.com/VisualStudio/feedback/details/574497/optional-parameter-of-type-string-in-a-attribute-constructor-cannot-be-null


Это явно ошибка компилятора. Спасибо, что привлекли мое внимание.

Предполагается, что здесь предполагается, что компилятор должен понимать, что необязательное выражение значения неявно преобразуется в формальный тип параметра, а затем обрабатывает выражение как постоянное выражение этого типа. То, что он на самом деле делает, относится к выражению как к необнужденному нулевому литералу, что неверно.

Вы можете обойти ошибку, превратив константу в явно типизированную:

public AdministratorSettingValidationAttribute(AdministratorSettingDataType administratorSettingDataType, Type enumerationType = (Type)null) 

Исправление, вероятно, простое, но я не могу обещать, что исправление будет в следующей версии С#; Я не уверен, что такое расписание для принятия некритических исправлений ошибок на этом этапе.

Еще раз спасибо и приносим извинения за неудобства.

Ответ 2

Это пахнет ошибкой компилятора. Классы атрибутов являются "специальными" классами таким образом, что их можно использовать в качестве метаданных. Компилятор С# позволяет вам использовать их по-другому, чем обычные классы, и поэтому мы можем предположить, что в компиляторе С# существует (частичная) пользовательская реализация для компиляции использования классов атрибутов. (Может ли кто-нибудь проверить это на моно?)

Тем не менее, я сделал некоторые тесты и обнаружил, что только при использовании конструктора атрибута, который задает значение по умолчанию для параметра как null без указания пользовательского значения этого атрибута, компилятор дает нам ошибку. Мой тестовый код:

class TestAttribute : Attribute
{
    public TestAttribute(object test = null) { }
    //public TestAttribute(int test = 0) { } 

    public void TestMethod(object test = null) { }
}

class TestClass
{
    public TestClass(object test  = null) { }
}

[Test()] // crashes
//[Test()] // Works when using the constructor taking an int
//[Test(null)] // works
class Program
{
    static void Main(string[] args)
    {
        TestClass t = new TestClass(); // works

        TestAttribute a = typeof(Program).GetCustomAttributes(typeof(TestAttribute), false).Cast<TestAttribute>().First();

        a.TestMethod(); // works
    }
}

(Протестировано с VS 2010 под .NET 4.0, может ли кто-нибудь проверить это с помощью моно?)

Обратите внимание, что атрибуты уже позволяют вам обращаться к свойствам так, как если бы они были необязательными, поэтому вы могли бы сделать свой необязательный параметр свойством (если это еще не так, и удалить его из конструктора.Это по-прежнему позволяет вам писать [Test (null, MyProperty = null)]