Это ошибка необязательных параметров компилятора C # 4.0? - PullRequest
13 голосов
/ 18 июня 2011

Я пишу пользовательский атрибут безопасности и получил странное поведение компилятора ... Когда я использую атрибут в том же файле, значения параметров по умолчанию работают нормально:

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, выглядит очень странно ...

1 Ответ

13 голосов
/ 18 июня 2011

Так что у меня нет точного ответа, но я взял его так далеко, как только мог, изучив его. Я думаю, я понимаю, почему это происходит, когда вы наследуете от 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 к коду. Я предполагаю, что это создает какие-то метаданные для сборки. Он должен делать это каким-то упорядоченным образом, чтобы не видеть необязательный параметр до тех пор, пока он не пройдет класс Program. Затем он должен каким-то образом использовать эти метаданные в процессе сборки, и именно здесь вы видите сбой. Для более подробной информации мы будем надеяться, что кто-то, кто знает компилятор, то есть Эрик, может пролить свет на это. Я бы отправил его на connect.microsoft.com в качестве одного из предложенных комментариев, так как кажется, что это ошибка, вызванная порядком прохождения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...