{"id":30263,"date":"2006-08-02T07:00:00","date_gmt":"2006-08-02T14:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/08\/02\/the-implementation-of-anonymous-methods-in-c-and-its-consequences-part-1\/"},"modified":"2006-08-02T07:00:00","modified_gmt":"2006-08-02T14:00:00","slug":"the-implementation-of-anonymous-methods-in-c-and-its-consequences-part-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060802-00\/?p=30263","title":{"rendered":"The implementation of anonymous methods in C# and its consequences (part 1)"},"content":{"rendered":"<p>\nYou may not even have realized that\nthere are two types of anonymous methods.\nI&#8217;ll call them the easy kind and the hard kind,\nnot because they&#8217;re actually easy and hard for you the programmer,\nbut because they are easy and hard for the compiler.\n<\/p>\n<p>\nThe easy kind is the anonymous method that doesn&#8217;t use any local variables\nfrom its lexically-enclosing method.\nThese are anonymous methods that could have been their own separate\nmember functions; all the anonymization does is save you\nthe trouble of coming up with names for them:\n<\/p>\n<pre>\nclass MyClass1 {\n int v = 0;\n delegate void MyDelegate(string s);\n MyDelegate MemberFunc()\n {\n  int i = 1;\n  return delegate(string s) {\n          System.Console.WriteLine(s);\n         };\n  }\n}\n<\/pre>\n<p>\nThis particular anonymous method doesn&#8217;t access any <code>MyClass1<\/code>\nmembers, nor does it access the local variables of the\n<code>MemberFunc<\/code> function; therefore, it can be\nconverted to a static method of the <code>MyClass1<\/code> class:\n<\/p>\n<pre>\nclass MyClass1_converted {\n int v = 0;\n delegate void MyDelegate(string s);\n <font COLOR=\"blue\">\/\/ Autogenerated by the compiler\n static void __AnonymousMethod$0<\/font>(string s)\n {\n  System.Console.WriteLine(s);\n }\n MyDelegate MemberFunc()\n {\n  int i = 1;\n  return <font COLOR=\"blue\">__AnonymousMethod$0<\/font>;\n  \/\/ which is in turn shorthand for\n  \/\/ return new MyDelegate(MyClass1.__AnonymousMethod$0);\n  }\n}\n<\/pre>\n<p>\nAll the compiler did was give your anonymous methods a name\nand use that name in place of the &#8220;<code>delegate (...) { ... }<\/code>&#8220;.\n(Note that all compiler-generated names I use here are\npurely illustrative.\nThe actual compiler-generated name will be something different.)\n<\/p>\n<p>\nOn the other hand, if your anonymous method used the <code>this<\/code>\nparameter, then that makes it an instance method instead of a\nstatic method:\n<\/p>\n<pre>\nclass MyClass2 {\n int v = 0;\n delegate void MyDelegate(string s);\n MyDelegate MemberFunc()\n {\n  int i = 1;\n  return delegate(string s) {\n          System.Console.WriteLine(\"{0} {1}\", v, s);\n         };\n  }\n}\n<\/pre>\n<p>\nThe anonymous method in <code>MyClass2<\/code>\nuses the <code>this<\/code> keyword\nimplicitly (to access the member variable <code>v<\/code>).\nTherefore, the conversion is to an instance member rather\nthan to a static member.\n<\/p>\n<pre>\nclass MyClass2_converted {\n int v = 0;\n delegate void MyDelegate(string s);\n <font COLOR=\"blue\">\/\/ Autogenerated by the compiler\n void __AnonymousMethod$0<\/font>(string s)\n {\n  System.Console.WriteLine(\"{0} {1}\", v, s);\n }\n MyDelegate MemberFunc()\n {\n  int i = 1;\n  return <font COLOR=\"blue\">this.__AnonymousMethod$0<\/font>;\n  \/\/ which is in turn shorthand for\n  \/\/ return new MyDelegate(this.__AnonymousMethod$0);\n  }\n}\n<\/pre>\n<p>\nSo far, we&#8217;ve only dealt with the easy cases.\nThe transformation is local and not particularly complicated.\nThese are the sorts of transformations you could make yourself\nwithout too much difficulty\nin the absence of anonymous methods.\n<\/p>\n<p>\nThe hard case is where things get interesting.\nThe body of an anonymous method is permitted to access the\nlocal variables of its lexically-enclosing method,\nin which case the compiler needs to keep those variables alive\nso that the body of your anonymous method can access them.\nHere&#8217;s a sample anonymous method that accesses local variables\nfrom its lexically-enclosing method:\n<\/p>\n<pre>\nclass MyClass3 {\n int v = 0;\n delegate void MyDelegate(string s);\n MyDelegate MemberFunc()\n {\n  int i = 1;\n  return delegate(string s) {\n          System.Console.WriteLine(\"{0} {1} {2}\", i++, v, s);\n         };\n  }\n}\n<\/pre>\n<p>\nIn this example, the anonymous method prints\n&#8220;1 v s&#8221; the first time it is called,\nthen &#8220;2 v s&#8221; the second time it is called,\nand so on, with the integer increasing by one.\n(And where <code>v s<\/code> are the current values of <code>v<\/code>\nand <code>s<\/code>, of course.)\nThis happens because the <code>i<\/code> variable that the\nanonymous method is accessing is the same one each time,\nand it&#8217;s the same <code>i<\/code> that the <code>MemberFunc<\/code>\nmethod was using, too.\nIf the function were rewritten as\n<\/p>\n<pre>\nclass MyClass4 {\n int v = 0;\n delegate void MyDelegate(string s);\n MyDelegate MemberFunc()\n {\n  int i = 0;\n  MyDelegate d = delegate(string s) {\n          System.Console.WriteLine(\"{0} {1} {2}\", i++, v, s);\n         };\n  i = 1;\n  return d;\n  }\n}\n<\/pre>\n<p>\nthe behavior would be the same as in <code>MyClass3<\/code>.\nThe creation of the delegate from the anonymous method does\n<strong>not<\/strong> make a copy of the <code>i<\/code>\nvariable;\nchanges to the <code>i<\/code> variable in the <code>MemberFunc<\/code>\nare visible to the anonymous method because both are accessing\nthe <strong>same<\/strong>\nvariable.\n<\/p>\n<p>\nWhen faced with this &#8220;hard&#8221; type of anonymous method, wherein variables\nare shared with the lexically-enclosing method,\nthe compiler generates a helper class:\n<\/p>\n<pre>\nclass MyClass3_converted {\n int v = 0;\n delegate void MyDelegate(string s);\n <font COLOR=\"blue\">\/\/ Autogenerated by the compiler\n class __AnonymousClass$0 {\n  MyClass this$0;\n  int i;\n  public void __AnonymousMethod$0<\/font>(string s)\n  {\n    System.Console.WriteLine(\"{0} {1} {2}\", i++, <font COLOR=\"blue\">this$0<\/font>.v, s);\n  }<font COLOR=\"blue\">\n }<\/font>\n MyDelegate MemberFunc()\n {\n  <font COLOR=\"blue\">__AnonymousClass$0 locals$ = new __AnonymousClass$0();\n  locals$.this$0 = this;\n  locals$.<\/font>i = 0;\n  return <font COLOR=\"blue\">locals$.__AnonymousMethod$0<\/font>;\n  \/\/ which is in turn shorthand for\n  \/\/ return new MyDelegate(locals$.__AnonymousMethod$0);\n  }\n}\n<\/pre>\n<p>\nWow, there was a lot of rewriting this time.\nA helper class was created to contain the local variables\nthat were shared between the <code>MemberFunc<\/code> function\nand the anonymous method (in this case, just the variable <code>i<\/code>),\nas well as the hidden <code>this<\/code> parameter\n(which I have called <code>this$<\/code>).\nIn the <code>MemberFunc<\/code> function,\naccess to that shared variable is done through\nthis anonymous class, and the anonymous method that you wrote\nis an anonymous method on the anonymous class.\n<\/p>\n<p>\nNotice that the assignment to <code>i<\/code> in\n<code>MemberFunc<\/code> modifies the copy inside <code>locals$<\/code>,\nwhich is the same object that the anonymous method will be using when it runs.\nThat&#8217;s why it prints &#8220;1 v s&#8221; the first time:\nThe value had already been changed to&nbsp;1 by the time the\ndelegate ran for the first time.\n<\/p>\n<p>\nThose who have done a good amount of C++ programming\n(or C#&nbsp;1.0 programming) are well familiar with this technique,\nsince C++ callbacks typically are given only one context variable;\nthat context variable is usually a pointer to a larger structure\nthat contains all the complex context you really want to operate on.\nC#&nbsp;1.0 programmers went through a similar exercise.\nThe &#8220;hard&#8221; type of anonymous method provides syntactic sugar\nthat saves you the hassle of having to declare and manage the helper class.\n<\/p>\n<p>\nIf you thought about it some, you&#8217;d have realized that\nthe way it&#8217;s done is pretty much the only way it could have been done.\nIt turns out that most computer programming doesn&#8217;t consist of being\nclever or making hard decisions.\nYou just have one kernel of an idea (&#8220;hey let&#8217;s have anonymous\nmethods&#8221;) and then the rest is just doing what has to be done,\nno actual decisions needed.\nYou just do the obvious thing.\nMost programming consists of just doing the obvious thing.\n<\/p>\n<p>\nOkay, so that&#8217;s a quick introduction to the implementation of\nanonymous methods in C#.\nMind you, this information isn&#8217;t just for your personal edification.\nIt&#8217;s actually important that you understand how these works\n(and not just treat it as &#8220;magic&#8221;),\nbecause lack of said understanding can lead to subtle programming errors.\nWe&#8217;ll look at those types of errors over the next few days.\n<\/p>\n<p>\n<b>Update<\/b>: This behavior\n<a>\nchanged in Visual Studio 2015<\/a>\nwith\nthe switch to the Roslyn compiler.\nFor performance reasons,\nanonymous methods are now always instance methods, even if they\ncapture nothing.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>First we&#8217;ll look at how they&#8217;re implemented.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-30263","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>First we&#8217;ll look at how they&#8217;re implemented.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30263","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=30263"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30263\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=30263"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=30263"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=30263"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}