Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a custom attribute appear both in IL and Metadata?

There are two attributes like this:

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

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

They are pretty simple, don't do anything.

And there is a method that is decorated with those two attributes:

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

Now if I compile the code and decompile it with IL Dasm, I'll see the IL code of method "Hello" is like this:

.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 
}

We can see the Test1Attribute and Test2Attribute are both in the IL code. And its Metadata is like this:

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: ()

Again, both the attributes are also there in the Metadata.

So I am curious about:

  1. Why do they appear both in IL and Metadata?
  2. What does

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

mean? It does not look like instruction. So what are they? What do they do?

Thanks

like image 846
Cui Pengfei 崔鹏飞 Avatar asked Feb 25 '23 15:02

Cui Pengfei 崔鹏飞


1 Answers

An attribute is just a class, note that you used the class keyword to declare one. Every class has a constructor, even if you don't write one yourself. The name for the constructor method is .ctor(). Clearly, with any method you get the IL for the code in the method body.

Parameters of a method have their own metadata. Used here to describe what attribute is applied. The .param directive gives the parameter number, the .custom directive gives the associated attribute. This is annotation in the IL syntax, it doesn't physically exist inside the method IL.

The metadata structure is sophisticated with dozens of tables, a disassembler rewrites it to make it more comprehensive. Ecma 335 has everything you need if you want to find out what it really looks like.

like image 84
Hans Passant Avatar answered Mar 15 '23 04:03

Hans Passant