Аргумент атрибута должен быть постоянной ошибкой при использовании необязательного параметра в конструкторе атрибутов
Может ли кто-нибудь объяснить, почему работает этот код:
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;
}
... вызывает ошибку времени компиляции:
" Аргумент атрибута должен быть константным выражением, выражением типа или выражением выражения массива типа параметра атрибута".
Ответы
Ответ 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)]