Почему пользовательский атрибут появляется как в IL, так и в метаданных? - PullRequest
4 голосов
/ 02 апреля 2011

Есть два атрибута, подобных этому:

[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = true)]
sealed class Test1Attribute : Attribute
{ }

[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = true)]
sealed class Test2Attribute : Attribute
{ }

Они довольно простые, ничего не делают.

И есть метод, который украшен этими двумя атрибутами:

public void Hello([Test1]string arg, [Test2] string arg2) { }

Теперь, если я скомпилирую код и декомпилирую его с помощью IL Dasm, я увижу, что код IL метода "Hello" выглядит следующим образом:

.method public hidebysig instance void Hello(int32 arg, int32 arg2) cil managed
{
    .param [1]
    .custom instance void ConsoleApplication1.Test1Attribute::.ctor()
    .param [2]
    .custom instance void ConsoleApplication1.Test2Attribute::.ctor()
    .maxstack 8
    L_0000: nop 
    L_0001: ret 
}

Мы видим, что Test1Attribute и Test2Attribute находятся в коде IL. И его метаданные выглядят так:

MethodName: Hello (06000005)
    Flags     : [Public] [HideBySig] [ReuseSlot]  (00000086)
    RVA       : 0x0000206b
    ImplFlags : [IL] [Managed]  (00000000)
    CallCnvntn: [DEFAULT]
    hasThis 
    ReturnType: Void
    2 Arguments
        Argument #1:  String
        Argument #2:  String
    2 Parameters
        (1) ParamToken : (08000002) Name : arg flags: [none] (00000000)
        CustomAttribute #1 (0c000010)
        -------------------------------------------------------
            CustomAttribute Type: 06000001
            CustomAttributeName: ConsoleApplication1.Test1Attribute :: instance void .ctor()
            Length: 4
            Value : 01 00 00 00                                      >                <
            ctor args: ()

        (2) ParamToken : (08000003) Name : arg2 flags: [none] (00000000)
        CustomAttribute #1 (0c000012)
        -------------------------------------------------------
            CustomAttribute Type: 06000002
            CustomAttributeName: ConsoleApplication1.Test2Attribute :: instance void .ctor()
            Length: 4
            Value : 01 00 00 00                                      >                <
            ctor args: ()

Опять же, оба атрибута также присутствуют в Метаданных.

Так что мне интересно:

  1. Почему они появляются как в IL, так и в метаданных?
  2. Что значит

    .param [1] .custom instance void ConsoleApplication1.Test1Attribute ::. ctor () .param [2] .custom instance void ConsoleApplication1.Test2Attribute ::. ctor ()

означает? Это не похоже на инструкцию. Так что они? Что они делают?

Спасибо

Ответы [ 2 ]

4 голосов
/ 02 апреля 2011

Пользовательские атрибуты - это фрагменты данных, которые можно прикрепить практически к любому фрагменту метаданных. Если вы хотите получить полную информацию - получите ECMS 335 Spec Page 231 основы. Страница 242 содержит информацию о таблице метаданных CustomAttribute, а формат сериализации, используемый для хранения данных атрибута, приведен на стр. 295 (все номера страниц указаны на фактической странице pdf-файла).

Ответы на ваши вопросы:

  1. Два участника: а. Вы смотрите на 2 представления метаданных выше (1. IL с метаданными метода (и параметра) и 2. подробное представление метаданных - минус IL) б. ILDasm показывает вам части метода, которые необходимы для выполнения. Что может показаться странным, так это то, что сигнатура метода не включает атрибуты - это потому, что сигнатура метода - это просто типы параметров. Любые атрибуты, прикрепленные к параметрам, относятся только к параметрам, а не к подписи ... поэтому ILDasm показывает их тоже, но ниже подписи.

  2. Это десериализованные и связанные метаданные атрибутов, которые хранятся и привязываются к параметрам. В вашем случае это просто вызов конструктора по умолчанию, но в более сложном случае у вас будет вызов конструктора и параметров данных, которые также хранятся в сериализованных битах.

4 голосов
/ 02 апреля 2011

Атрибут - это просто класс, обратите внимание, что вы использовали ключевое слово class для его объявления.У каждого класса есть конструктор, даже если вы не пишете его самостоятельно.Имя метода конструктора - .ctor ().Понятно, что при любом методе вы получаете IL для кода в теле метода.

Параметры метода имеют свои собственные метаданные.Используется здесь, чтобы описать, какой атрибут применяется.Директива .param дает номер параметра, а директива .custom - связанный атрибут.Это аннотация в синтаксисе IL, она физически не существует внутри метода IL.

Структура метаданных содержит десятки таблиц, дизассемблер переписывает ее, чтобы сделать ее более полной. Ecma 335 имеет все необходимое, если вы хотите узнать, как это действительно выглядит.

...