这是一个C#4.0编译器可选参数bug吗?

con*_*low 13 c# attributes optional-parameters c#-4.0

我正在编写自定义安全属性并得到奇怪的编译器行为...当我在同一文件中使用该属性时,默认参数值工作正常:

using System.Security.Permissions;

[System.Serializable]
sealed class FooAttribute : CodeAccessSecurityAttribute {
    public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { }
    public override System.Security.IPermission CreatePermission() { return null; }
}

[Foo] class Program {
    static void Main(string[] args) { }
}
Run Code Online (Sandbox Code Playgroud)

但是当我将上面的代码分成两个文件时 - 文件1:

using System.Security.Permissions;

[System.Serializable]
sealed class FooAttribute : CodeAccessSecurityAttribute {
    public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { }
    public override System.Security.IPermission CreatePermission() { return null; }
}
Run Code Online (Sandbox Code Playgroud)

和文件2:

[Foo] class Program {
    static void Main(string[] args) { }
}
Run Code Online (Sandbox Code Playgroud)

我有一个编译器错误:

错误:'FooAttribute'不包含带0参数的构造函数

这只发生在CodeAccessSecurityAttribute继承者身上,看起来很奇怪......

Cra*_*nec 13

所以我没有一个确切的答案,但我尽可能地调查它.我想我理解为什么它会在你继承CodeAccessSecurityAttribute而不是SecurityAttribute. 你的情况下发生如果你看看在Foo继承CodeAccessSecurityAttribute它时应用属性时生成的IL 看起来像这样:

.permissionset demand = {class 'ConsoleApplication1.FooAttribute, ConsoleApplication1, Version=1.0.0.0, Culture=neutral' = {}}
Run Code Online (Sandbox Code Playgroud)

Foo从SecurityAttribute继承它看起来像这样:

.custom instance void ConsoleApplication1.FooAttribute::.ctor(valuetype [mscorlib]System.Security.Permissions.SecurityAction) = ( 01 00 02 00 00 00 00 00 ) 
Run Code Online (Sandbox Code Playgroud)

显然,CodeAccessSecurityAttribute通过应用属性大大改变了生成的IL.

如果我们将Foo声明更改为如下,则更多地查看IL

[Foo(SecurityAction.Demand)]
Run Code Online (Sandbox Code Playgroud)

我们得到以下IL:

.permissionset demand = {class 'ConsoleApplication1.FooAttribute, ConsoleApplication1, Version=1.0.0.0, Culture=neutral' = {}}
Run Code Online (Sandbox Code Playgroud)

它与我们没有指定可选参数时的情况相同.此外,我们不仅可以通过将属性和Program类拆分为单独的文件来导致错误,我们可以通过重新排列类中的文件来导致它,如下所示:

[Foo]
class Program
{

    static void Main(string[] args) {}


}

[System.Serializable]
sealed class FooAttribute : CodeAccessSecurityAttribute
{
    public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { }
    public override System.Security.IPermission CreatePermission() { return null; }
}
Run Code Online (Sandbox Code Playgroud)

如果我们使用类进行以下操作OtherOther2给出错误但是Program没有,那就更有趣了.只有Foo文件中前面的类才会出错

 [Foo]
 class Other
 {

 }

 [Foo]
 class Other2
 {
 }

 [System.Serializable]
 sealed class FooAttribute : CodeAccessSecurityAttribute
 {
      public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { }
      public override System.Security.IPermission CreatePermission() { return null; }        }

 [Foo]
 class Program
 {

  static void Main(string[] args) {}
 }
Run Code Online (Sandbox Code Playgroud)

这对我说的是构建过程中的某个地方存在问题.我不太了解Code Access Security如何解决确切问题.必须有部分过程查看CodeAccessSecurityAttributes并尝试将SecurityAction应用于代码.我假设它为程序集构建了某种元数据.它必须以某种有序的方式执行此操作,以便在它已经通过Program类之后才会看到可选参数.然后,它必须在构建过程中以某种方式使用该元数据,这是您看到失败的地方.对于任何更多的细节,我们必须希望有人知道编译器,即埃里克可以阐明它.我会在connect.microsoft.com上提交它作为建议的评论之一,因为它似乎是由于遍历订单而导致的错误.