在属性构造函数中使用可选参数时,属性参数必须为常量错误

本文关键字:属性 参数 错误 常量 构造函数 | 更新日期: 2023-09-27 18:15:59

谁能解释一下这段代码的工作原理:

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;
    }

…导致编译时错误:"属性参数必须是属性参数类型的常量表达式、typeof表达式或数组创建表达式"。

在属性构造函数中使用可选参数时,属性参数必须为常量错误

UPDATE

这个bug是在去年7月报告的,现在已经修复了。该修复将出现在c#的下一个版本中。有关详细信息,请参阅此连接反馈项:

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) 

修复可能是直接的,但我不能保证修复将在c#的下一个版本;在这一点上,我不确定非关键错误修复的时间表是什么样的。

再次表示感谢,对给您带来的不便表示歉意。

我觉得这像是编译器的bug。属性类在某种程度上是"特殊的"类,它们可以被用作元数据。c#编译器允许你以不同于普通类的方式使用属性类,因此我们可以假设c#编译器中存在一个(部分的)自定义实现来编译属性类的使用。(谁能在mono上测试一下吗?)

也就是说,我做了一些测试,发现只有当使用一个属性的构造函数,指定参数的默认值为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
    }
}

(在。net 4.0下测试VS 2010,有人可以用mono测试吗?)

请注意,Attributes已经允许您像处理可选属性一样处理属性,因此您可以将可选参数设置为属性(如果还没有),并从构造函数中删除它。这仍然允许您编写[Test(null, MyProperty = null)]