{"id":3204,"date":"2010-11-30T17:25:00","date_gmt":"2010-11-30T17:25:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/subterranean-il-pseudo-custom-attributes\/"},"modified":"2021-04-29T15:30:55","modified_gmt":"2021-04-29T15:30:55","slug":"subterranean-il-pseudo-custom-attributes","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/subterranean-il-pseudo-custom-attributes\/","title":{"rendered":"Subterranean IL: Pseudo custom attributes"},"content":{"rendered":"<p>Custom attributes were designed to make the .NET framework extensible; if a .NET language needs to store additional metadata on an item that isn&#8217;t expressible in IL, then an attribute could be applied to the IL item to represent this metadata. For instance, the C# compiler uses <code>DecimalConstantAttribute<\/code> and <code>DateTimeConstantAttribute<\/code> to represent compile-time decimal or datetime constants, which aren&#8217;t allowed in pure IL, and <code>FixedBufferAttribute<\/code> to represent <code>fixed<\/code> struct fields.<\/p>\n<p><b>How attributes are compiled<\/b><\/p>\n<p>Within a .NET assembly are a series of tables containing all the metadata for items within the assembly; for instance, the <code>TypeDef<\/code> table stores metadata on all the types in the assembly, and <code>MethodDef<\/code> does the same for all the methods and constructors. Custom attribute information is stored in the <code>CustomAttribute<\/code> table, which has references to the IL item the attribute is applied to, the constructor used (which implies the type of attribute applied), and a binary blob representing the arguments and name\/value pairs used in the attribute application.<\/p>\n<p>For example, the following C# class: <\/p>\n<pre>[Obsolete(\"Please use MyClass2\", true)]\npublic class MyClass {\n    \/\/ ...\n}<\/pre>\n<p> corresponds to the following IL class definition: <\/p>\n<pre>.class public MyClass {\n    .custom instance void\n        [mscorlib]System.ObsoleteAttribute::.ctor(string, bool)\n        = { string('Please use MyClass2' bool(true) }\n    \/\/ ...\n}<\/pre>\n<p> and results in the following entry in the <code>CustomAttribute<\/code> table: <\/p>\n<pre>TypeDef(MyClass)\nMemberRef(ObsoleteAttribute::.ctor(string, bool))\nblob -&gt; {string('Please use MyClass2' bool(true)}<\/pre>\n<p> However, there are some attributes that don&#8217;t compile in this way.<\/p>\n<p><b>Pseudo custom attributes<\/b><\/p>\n<p>Just like there are some concepts in a language that can&#8217;t be represented in IL, there are some concepts in IL that can&#8217;t be represented in a language. This is where pseudo custom attributes come into play.<\/p>\n<p>The most obvious of these is <code>SerializableAttribute<\/code>. Although it looks like an attribute, it doesn&#8217;t compile to a <code>CustomAttribute<\/code> table entry; it instead sets the <code>serializable<\/code> bit directly within the <code>TypeDef<\/code> entry for the type. This flag is fully expressible within IL; this C#: <\/p>\n<pre>[Serializable]\npublic class MySerializableClass {}<\/pre>\n<p> compiles to this IL: <\/p>\n<pre>.class public serializable MySerializableClass {}<\/pre>\n<\/p>\n<p>For those interested, a full list of pseudo custom attributes is available <a href=\"http:\/\/blogs.msdn.com\/b\/adam_nathan\/archive\/2003\/04\/29\/56645.aspx\">here<\/a>. For the rest of this post, I&#8217;ll be concentrating on the ones that deal with P\/Invoke.<\/p>\n<p><b>P\/Invoke attributes<\/b><\/p>\n<p>P\/Invoke is built right into the CLR at quite a deep level; there are 2 metadata tables within an assembly dedicated solely to p\/invoke interop, and many more that affect it. Furthermore, all the attributes used to specify p\/invoke methods in C# or VB have their own keywords and syntax within IL. For example, the following C# method declaration: <\/p>\n<pre>[DllImport(\"mscorsn.dll\", SetLastError = true)]\n[return: MarshalAs(UnmanagedType.U1)]\nprivate static extern bool StrongNameSignatureVerificationEx(\n    [MarshalAs(UnmanagedType.LPWStr)] string wszFilePath,\n    [MarshalAs(UnmanagedType.U1)] bool fForceVerification,\n    [MarshalAs(UnmanagedType.U1)] ref bool pfWasVerified);<\/pre>\n<p> compiles to the following IL definition: <\/p>\n<pre>.method private static pinvokeimpl(\"mscorsn.dll\" lasterr winapi)\nbool marshal(unsigned int8)\nStrongNameSignatureVerificationEx(\n    string marshal(lpwstr) wszFilePath,\n    bool marshal(unsigned int8) fForceVerification,\n    bool&amp; marshal(unsigned int8) pfWasVerified) cil managed preservesig {}<\/pre>\n<p> As you can see, all the p\/invoke and marshal properties are specified directly in IL, rather than using attributes. And, rather than creating entries in <code>CustomAttribute<\/code>, a whole bunch of metadata is emitted to represent this information. This single method declaration results in the following metadata being output to the assembly: <\/p>\n<ul>\n<li>A <code>MethodDef<\/code> entry containing basic information on the method<\/li>\n<li>Four <code>ParamDef<\/code> entries for the 3 method parameters and return type<\/li>\n<li>An entry in <code>ModuleRef<\/code> to mscorsn.dll<\/li>\n<li>An entry in <code>ImplMap<\/code> linking <code>ModuleRef<\/code> and <code>MethodDef<\/code>, along with the name of the function to import and the pinvoke options (<code>lasterr winapi<\/code>)<\/li>\n<li>Four <code>FieldMarshal<\/code> entries containing the marshal information for each parameter.<\/li>\n<\/ul>\n<p> Phew!<\/p>\n<p><b>Applying attributes<\/b><\/p>\n<p>Most of the time, when you apply an attribute to an element, an entry in the <code>CustomAttribute<\/code> table will be created to represent that application. However, some attributes represent concepts in IL that aren&#8217;t expressible in the language you&#8217;re coding in, and can instead result in a single bit change (<code>SerializableAttribute<\/code> and <code>NonSerializedAttribute<\/code>), or many extra metadata table entries (the p\/invoke attributes) being emitted to the output assembly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Custom attributes were designed to make the .NET framework extensible; if a .NET language needs to store additional metadata on an item that isn&#8217;t expressible in IL, then an attribute could be applied to the IL item to represent this metadata. For instance, the C# compiler uses DecimalConstantAttribute and DateTimeConstantAttribute to represent compile-time decimal or&#8230;&hellip;<\/p>\n","protected":false},"author":186659,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538,2],"tags":[],"coauthors":[],"class_list":["post-3204","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3204","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/186659"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=3204"}],"version-history":[{"count":2,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3204\/revisions"}],"predecessor-version":[{"id":41973,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3204\/revisions\/41973"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=3204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=3204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=3204"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=3204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}