Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在属性构造函数中使用可选参数时,属性参数必须为常量错误_C#_.net_Visual Studio 2010 - Fatal编程技术网

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

C# 在属性构造函数中使用可选参数时,属性参数必须为常量错误,c#,.net,visual-studio-2010,C#,.net,Visual Studio 2010,有人能解释一下这段代码的工作原理吗: public class AdministratorSettingValidationAttribute : Attribute { public AdministratorSettingValidationAttribute(AdministratorSettingDataType administratorSettingDataType) { DataType = administratorSettingDataType;

有人能解释一下这段代码的工作原理吗:

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表达式或属性参数类型的数组创建表达式”

我觉得这好像是编译器的错误。属性类是“特殊”类,可以用作元数据。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
    }
}
class TestAttribute:属性
{
公共TestAttribute(对象测试=null){}
//公共测试属性(int test=0){}
public void TestMethod(object test=null){}
}
类TestClass
{
公共测试类(对象测试=null){}
}
[Test()]//崩溃
//[Test()]//在使用接受int的构造函数时有效
//[测试(空)]//工作正常
班级计划
{
静态void Main(字符串[]参数)
{
TestClass t=新的TestClass();//有效
TestAttribute a=typeof(程序).GetCustomAttributes(typeof(TestAttribute),false).Cast().First();
a、 TestMethod();//有效
}
}
(在.NET4.0下用VS2010进行测试,有人能用mono进行测试吗?)

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

UPDATE 该漏洞于去年7月报告,现已修复。该修复将出现在C#的下一版本中。有关详细信息,请参阅此连接反馈项:


这显然是一个编译器错误。谢谢你提醒我注意

这里应该发生的是,编译器应该意识到可选值表达式隐式转换为形式参数类型,然后将该表达式视为该类型的常量表达式。它实际上是将该表达式视为无类型的空文本,这是错误的

您可以通过将常量转换为显式类型的常量来解决此错误:

public AdministratorSettingValidationAttribute(AdministratorSettingDataType administratorSettingDataType, Type enumerationType = (Type)null) 
修复可能很简单,但我不能保证修复会出现在下一个版本的C中;我不确定在这一点上进行非关键错误修复的时间表是什么样的


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

Wow…这可能意味着如果在调用时使用可选参数,编译器会生成一些代码,以某种方式计算省略参数的值,而这与常量值要求相冲突吗?这可以解释问题,尽管应该有更多的解释我认为错误消息是可以理解的。@PavelGatilov-不,它不能。第一个观察结果是,在构造函数中使用非null的默认值是完全可以的。第二个观察结果是,每次访问属性时,它的构造函数都会像普通代码一样执行(Type.GetCustomAttributes(…).我想我们需要唤醒Eric Lippertone@PavelGatilov-使用属性时。编译器将属性用法编译为指定属性的位置的元数据。在这里,有一个名为ctor args的字段。当使用默认参数而在使用属性时未指定参数时,字段将包含“nothing”,这意味着JIT将确定我们的默认值。在Windows上使用Mono 2.10进行测试,编译和运行都很顺利。正如我对上述答案的评论中所指出的,Mono处理代码很好,因此它特定于Visual C编译器。对于Visual Studio 2010,如果我有“string myString=(string)null”它仍然不起作用(即使是显式转换)。此外,该链接给了我一个找不到的页面。@user276648该修复似乎只有在同一程序集中使用该属性时才起作用(在该程序集中定义了属性类)。如果该属性是在一个首先编译的程序集中定义的,并且该属性应用于另一个程序集中的代码元素(而另一个程序集引用了第一次编译的二进制文件),则修复程序不起作用。如果使用空字符串
,则可以绕过它
作为可选字符串参数的默认值。
string myString=(string)null
对我不起作用。
private const string NullString=null
也不起作用。我添加了一个重载构造函数,调用
this(val1,null)
。MSVS2013中仍然存在此错误,但使用可为空的类型字符串是可以的。