{"id":30253,"date":"2006-08-03T07:00:00","date_gmt":"2006-08-03T14:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/08\/03\/the-implementation-of-anonymous-methods-in-c-and-its-consequences-part-2\/"},"modified":"2006-08-03T07:00:00","modified_gmt":"2006-08-03T14:00:00","slug":"the-implementation-of-anonymous-methods-in-c-and-its-consequences-part-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060803-00\/?p=30253\/","title":{"rendered":"The implementation of anonymous methods in C# and its consequences (part 2)"},"content":{"rendered":"<p>\nLast time we took a look at how anonymous methods are implemented.\nToday we&#8217;ll look at a puzzle that can be solved with what we&#8217;ve learned.\nConsider the following program fragment:\n<\/p>\n<pre>\nusing System;\nclass MyClass {\n delegate void DelegateA();\n delegate void DelegateB();\n static DelegateB ConvertDelegate(DelegateA d)\n {\n  return (DelegateB)\n   Delegate.CreateDelegate(typeof(DelegateB), d.Method);\n }\n static public void Main()\n {\n  int i = 0;\n  ConvertDelegate(delegate { Console.WriteLine(0); });\n }\n}\n<\/pre>\n<p>\nThe <code>ConvertDelegate<\/code> method merely converts\na <code>DelegateA<\/code> to a <code>DelegateB<\/code>\nby creating a <code>DelegateB<\/code> with the same underlying\nmethod.\nSince the two delegate types use the same signature,\nthis conversion goes off without a hitch.\n<\/p>\n<p>\nBut now let&#8217;s make a small change to that <code>Main<\/code> function:\n<\/p>\n<pre>\n static public void Main()\n {\n  int i = 0;\n  \/\/ one character change - 0 becomes i\n  ConvertDelegate(delegate { Console.WriteLine(<font COLOR=\"blue\">i<\/font>); });\n }\n<\/pre>\n<p>\nNow the program crashes with a\n<code>System.ArgumentException<\/code> at the point where\nwe try to create the <code>DelegateB<\/code>.\nWhat&#8217;s going on?\n<\/p>\n<p>\nFirst,\nobserve that the overload of <code>Delegate.CreateDelegate<\/code>\nthat was used is one that can only be used to create delegates\nfrom static methods.\nNext, note that in <code>Test1<\/code>,\nthe anonymous method references neither its own members\nnor any local variables from its lexically-enclosing method.\nTherefore, the resulting anonymous method is\na &#8220;static anonymous method of the easy type&#8221;.\nSince the anonymous method is a static member,\nthe use of the &#8220;static members only&#8221; overload of\n<code>Delegate.CreateDelegate<\/code> succeeds.\n<\/p>\n<p>\nHowever, in <code>Test2<\/code>, the anonymous method dereferences the\n<code>i<\/code> variable from its lexically-enclosing method.\nThis forces the anonymous method to be a &#8220;anonymous method of the hard type&#8221;,\nand those anonymous methods use an anonymous instance member function\nof an anonymous helper class.\nAs a result,\n<code>d.Method<\/code> is an instance method, and the chosen overload of\n<code>Delegate.CreateDelegate<\/code> throws an invalid parameter\nexception since it works only with static methods.\n<\/p>\n<p>\nThe solution is to use a different overload of\n<code>Delegate.CreateDelegate<\/code>,\none that work with either static or instance member functions.\n<\/p>\n<pre>\n DelegateB ConvertDelegate(DelegateA d)\n {\n  return (DelegateB)\n   Delegate.CreateDelegate(typeof(DelegateB), <font COLOR=\"blue\">d.Target,<\/font> d.Method);\n }\n<\/pre>\n<p>\nThe <code>Delegate.CreateDelegate(Type, Object, MethodInfo)<\/code>\noverload creates a delegate for a static method if the\n<code>Object<\/code> parameter is <code>null<\/code> or\na delegate for an instance method if the <code>Object<\/code>\nparameter is non-<code>null<\/code>.\nHardly by coincidence, that is exactly what <code>d.Target<\/code> produces.\nIf the original delegate is for a static method, then\n<code>d.Target<\/code> is <code>null<\/code>; otherwise, it is\nthe object for which the instance method is to be invoked on.\n<\/p>\n<p>\nThis fix, therefore, makes the <code>ConvertDelegate<\/code>\nfunction handle conversion of delegates for either static or\ninstance methods.\nWhich is a good thing, because it may now be called upon to\nconvert delegates for instance methods as well as static ones.\n<\/p>\n<p>\nOkay, this time we were lucky that the hidden gotcha of anonymous\nmethods resulted in an exception.\nNext time, we&#8217;ll see a gotcha that merely results in incorrect\nbehavior that will probably take you forever to track down.\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>When the anonymous class becomes visible.<\/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-30253","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>When the anonymous class becomes visible.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30253","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=30253"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30253\/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=30253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=30253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=30253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}