{"id":3362,"date":"2015-09-13T19:56:45","date_gmt":"2015-09-13T19:56:45","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=3362"},"modified":"2015-09-13T19:56:45","modified_gmt":"2015-09-13T19:56:45","slug":"creating-awaitable-types","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/creating-awaitable-types\/","title":{"rendered":"Creating awaitable types"},"content":{"rendered":"<p>If you&#8217;ve used async\/await in your applications, you&#8217;ll generally await a Task, but you can actually make your own type awaitable. Let&#8217;s look at how we&#8217;d do this.<\/p>\n<p><strong>Why are Task&#8217;s awaitable?<\/strong><\/p>\n<p>A Task is awaitable, not because it&#8217;s a Task type, but its because it supports a specific method name which returns a TaskAwaiter or TaskAwaiter<T> for the Task<T> type. So let&#8217;s take a look at what this method looks like<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic TaskAwaiter GetAwaiter()\r\n<\/pre>\n<p>So it&#8217;s really that simple, if we want to make our object awaitable we simply define the same method in our type.<\/p>\n<p><strong>What is a TaskAwaiter?<\/strong><\/p>\n<p>A TaskAwaiter is a struct which implements the ICriticalNotifyCompletion interface and the INotifyCompletion interface (the ICriticalNotifyCompletion  derives from the INotifyCompletion). But this still wouldn&#8217;t make the TaskAwaiter awaitable it also needs the property IsCompleted and the method GetResult &#8211; more on this in &#8220;the rules for an &#8220;Awaiter&#8221; type&#8221; below.<\/p>\n<p><em>It does seem strange that these methods weren&#8217;t all put into a single interface, but there you have it.<\/em><\/p>\n<p><strong>How do I create a bare minimum awaitable type?<\/strong><\/p>\n<p>Let&#8217;s first review the rules for making our type awaitable<\/p>\n<ul>\n<li>Our type should have a method named GetAwaiter which takes no arguments and returns a suitable &#8220;Awaiter&#8221; type <\/li>\n<\/ul>\n<p>and now the rules for an &#8220;Awaiter&#8221; type<\/p>\n<ul>\n<li>The type should implement the INotifyCompletion interface or the ICriticalNotifyCompletion interface<\/li>\n<li>It should have a IsCompleted property of type boolean<\/li>\n<li>It should have a GetResult method which returns void or a result value<\/li>\n<ul>\n<p>and now let&#8217;s put this together into a somewhat pointless type which demonstrates a bare minimum set of requirements to get this type to be awaitable<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class MyObject\r\n{\r\n   public MyAwaiter GetAwaiter()\r\n   {\r\n      return new MyAwaiter();\r\n   }\r\n}\r\n\r\npublic struct MyAwaiter\r\n{\r\n   public void OnCompleted(Action continuation)\r\n   {\r\n      continuation();\r\n   }\r\n\r\n   public bool IsCompleted { get; private set; }\r\n\r\n   public void GetResult()\r\n   {\t\t\t\r\n   }\r\n}\r\n<\/pre>\n<p>and now in use, we would have something like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar o = new MyObject();\r\nawait o;\r\n<\/pre>\n<p><em>Note: if you do not call the conitnuation() action in the OnCompleted method the code will block indefinitely.<\/em><\/p>\n<p>The flow of this code goes as follows&#8230;<\/p>\n<p><em>await o<\/em> is called, this calls <em>GetAwaiter<\/em> on MyObject which returns a <em>MyAwaiter<\/em>. Next <em>IsCompleted<\/em> is checked, if the awaiter has already completed then control returns to the line after the await, if it&#8217;s false <em>OnCompleted<\/em> is called which basically blocks until the continuation is called, finally the <em>GetResult<\/em> method is called.<\/p>\n<p><strong>Extension methods that are awaitable<\/strong><\/p>\n<p>So we&#8217;ve discussed creating our own type, making it awaitable and even creating an awaiter type, but another approach which one might use is creating extension methods and instead of going to the hassle of creating an awaiter type, we&#8217;ll simply reuse the TaskCompletionSource type which can be used as a puppet task.<\/p>\n<p>Let&#8217;s go straight to some code which I&#8217;ve unashamedly lifted from Stephen Toub&#8217;s blog post <a href=\"http:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2011\/01\/13\/10115642.aspx\" target=\"_blank\">await anything<\/a>.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic static TaskAwaiter&lt;int&gt; GetAwaiter(this Process process)\r\n{\r\n   var tcs = new TaskCompletionSource&lt;int&gt;();\r\n   process.EnableRaisingEvents = true;\r\n   process.Exited += (s, e) =&gt; tcs.TrySetResult(process.ExitCode);\r\n   if (process.HasExited)\r\n   {\r\n      tcs.TrySetResult(process.ExitCode);\r\n   }\r\n   return tcs.Task.GetAwaiter();\r\n}\r\n<\/pre>\n<p>and we would use this as follows<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nawait Process.Start(\u201cnotepad.exe\u201d)\r\n<\/pre>\n<p>Looking at the extension method you can see we&#8217;re going to use the TaskCompletion classes GetAwaiter to return the awaiter type (in this case a TaskAwaiter<int>) and we simply try to set the result on the TaskCompletionSource if, or when, the process exits.<\/p>\n<p><strong>References<\/strong><\/p>\n<p><a href=\"http:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2011\/01\/13\/10115642.aspx\" target=\"_blank\">await anything<\/a><br \/>\n<a href=\"http:\/\/blogs.msdn.com\/b\/lucian\/archive\/2011\/04\/15\/async-ctp-refresh-design-changes.aspx\" target=\"_blank\">Design change: new &#8220;await&#8221; pattern for greater efficiency<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;ve used async\/await in your applications, you&#8217;ll generally await a Task, but you can actually make your own type awaitable. Let&#8217;s look at how we&#8217;d do this. Why are Task&#8217;s awaitable? A Task is awaitable, not because it&#8217;s a Task type, but its because it supports a specific method name which returns a TaskAwaiter [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-3362","post","type-post","status-publish","format-standard","hentry","category-c"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/3362","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=3362"}],"version-history":[{"count":12,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/3362\/revisions"}],"predecessor-version":[{"id":3379,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/3362\/revisions\/3379"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=3362"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=3362"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=3362"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}