Что означает [opt] в MSIL? - PullRequest
9 голосов
/ 31 марта 2011

Мне показалась очень интересной функция «необязательных параметров» в C # 4.0, поэтому я попытался выяснить, как они это сделали. поэтому я написал такой метод:

private static void A(int a = 5) { }

Скомпилировал, затем декомпилировал в IL DASM, это код IL:

.method private hidebysig static void  A([opt] int32 a) cil managed
{
  .param [1] = int32(0x00000005)
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Program::A

И оно имеет это в своих метаданных:

(1) ParamToken: (08000002) Имя: флаги: [Необязательно] [HasDefault] (00001010) По умолчанию: (I4) 5

Итак, я последовал подсказке и написал такой метод:

private static void B([Optional, DefaultParameterValue(78)]int b) { }

Скомпилировал и декомпилировал, и я обнаружил, что компилятор C # сгенерировал практически идентичный код MSIL для методов A и B (кроме имени).

Как мы видим, в коде IL нет никаких признаков атрибутов, и он чувствовал себя не так, поэтому я написал собственный атрибут, подобный этому:

[AttributeUsage(AttributeTargets.Parameter)]
public class MyTestAttribute : Attribute
{
}

Затем использовал его в методе C следующим образом:

private static void C([MyTest]int c) { }

Скомпилировал, а затем декомпилировал, и хах, я нашел это:

.method private hidebysig static void  C(int32 c) cil managed
{
  .param [1]
  .custom instance void ConsoleApplication1.MyTestAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Program::C

Вторая строка тела метода вызывает ctor моего пользовательского атрибута.

Так что это приводит к моим сомнениям:

  1. Что означает [opt]? Я имею в виду тот, который появляется перед параметром метода A и B.
  2. Почему метод C вызывает конструктор Атрибута, который применяется к его параметру, а методы A и B - нет?
  3. Я не могу найти никаких признаков DefaultParameterValueAttribute в метаданных, но я могу найти OptionalAttribute и MyTestAttribute. Это почему? Я что-то упускаю?

Заранее спасибо.

Ответы [ 2 ]

10 голосов
/ 31 марта 2011

Компилятору C # не нужно выдавать атрибуты, поскольку таблица метаданных Param уже может описывать необязательные значения и значения по умолчанию через столбец Flags.

С 23.1.13 в ECMA 335 :

Flag            Value   Description
-----------------------------------------------------
In              0x0001  Parameter is [In]  
Out             0x0002  Parameter is [Out]  
Optional        0x0010  Parameter is optional  
HasDefault      0x1000  Parameter has a default value  
HasFieldMarshal 0x2000  Parameter has FieldMarshal  

Параметр может иметь значение флага, которое указывает, что оно является необязательным и имеет значение по умолчанию (0x0010 | 0x1000). Параметры, имеющие значение по умолчанию, будут иметь связанный токен в таблице метаданных констант.

В таблице метаданных констант есть столбец Parent, который будет указанным токеном Param, и столбец Value, который будет индексом в куче больших двоичных объектов, где хранится значение по умолчанию.

Итак, чтобы ответить на ваши вопросы:

  1. [opt] означает, что в столбце Flags для токена Param установлен флаг Optional.
  2. Как я уже говорил выше, я предполагаю, что компилятор C # распознает атрибуты Optional / DefaultParameterValue и просто конвертирует их во флаги параметров.
  3. Редактировать : Похоже, что компилятор C # испускает неиспользуемый TypeRef для OptionalAttribute, несмотря на использование флага Optional для параметра. Однако он не генерирует TypeRef для DefaultParameterValueAttribute. Это может быть небольшая ошибка компилятора для создания неиспользуемых TypeRefs / MemberRefs.
2 голосов
/ 31 марта 2011

2/3; есть несколько атрибутов, которые компилятор интерпретирует как метаданные IL, а не атрибуты; похоже, это именно тот случай; [Serializable] является еще одним примером. Данные по умолчанию есть: Default: (I4) 5 - не все атрибуты в коде становятся атрибутами в метаданных (опять же, я смотрю на [Serializable] здесь)


по этому поводу [Serializable] (комментарии); Вот пример:

[Description("abc")]
class Foo { }

[Serializable]
class Bar { }

, для которого ядро ​​IL:

.class private auto ansi beforefieldinit Foo
    extends [mscorlib]System.Object
{
    .custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') }
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

}
.class private auto ansi serializable beforefieldinit Bar
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

}

В Foo (для некоторого произвольного атрибута) мы получаем:

.custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') }

Однако это не относится к [Serializable]; вместо этого это часть типа:

.class private auto ansi serializable beforefieldinit Bar
...