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

Является ли эта ошибка компилятора С# 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) { }
}

Но когда я разделяю приведенный выше код на два файла - файл 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; }
}

И файл 2:

[Foo] class Program {
    static void Main(string[] args) { }
}

У меня ошибка компилятора:

Ошибка: 'FooAttribute' не содержит конструктора, который принимает 0 аргументов

Это происходит только с наследниками CodeAccessSecurityAttribute, выглядит очень странно...

4b9b3361

Ответ 1

Итак, у меня нет точного ответа, но я взял его, насколько мог, заглядывая в него. Я думаю, что я понимаю, почему это происходит, когда вы наследуете от CodeAccessSecurityAttribute, а не SecurityAttribute.. Если вы посмотрите на IL, сгенерированный при применении атрибута Foo, когда он наследует от CodeAccessSecurityAttribute, он выглядит так:

.permissionset demand = {class 'ConsoleApplication1.FooAttribute, ConsoleApplication1, Version=1.0.0.0, Culture=neutral' = {}}

Когда Foo наследуется от SecurityAttribute, он выглядит так:

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

Очевидно, что CodeAccessSecurityAttribute радикально изменяет IL, сгенерированный с помощью применения атрибута.

Глядя на IL больше, если мы изменим объявление Foo, чтобы выглядеть следующим образом

[Foo(SecurityAction.Demand)]

Получим следующий IL:

.permissionset demand = {class 'ConsoleApplication1.FooAttribute, ConsoleApplication1, Version=1.0.0.0, Culture=neutral' = {}}

Это то же самое, что и когда мы не указали необязательный параметр. Кроме того, мы можем вызвать ошибку не только путем разделения атрибута и класса 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; }
}

Еще интереснее, если мы сделаем следующее с классом Other и Other2, дадим ошибку, но 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) {}
 }

То, что это говорит мне, заключается в том, что в процессе сборки есть проблема. Я не знаю достаточно о том, как работает Code Access Security, чтобы указать на то, какая именно проблема. Должна быть часть процесса, которая рассматривает CodeAccessSecurityAttributes и делает что-то с попыткой применить SecurityAction к коду. Я предполагаю, что он создает какие-то метаданные для сборки. Он должен делать это каким-то упорядоченным способом, чтобы не видеть необязательный параметр, пока он уже не прошел класс программы. Затем он должен использовать эти метаданные каким-то образом во время процесса сборки, и именно там вы видите сбой. Для более подробной информации нам нужно надеяться, что кто-то знает компилятор, т.е. Эрик может пролить свет на него. Я бы отправил его на connect.microsoft.com в качестве одного из комментариев, предложенных, поскольку кажется, что ошибка, вызванная перемещением вещей, проходит.