{"id":103271,"date":"2019-12-27T07:00:00","date_gmt":"2019-12-27T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103271"},"modified":"2019-12-26T20:46:25","modified_gmt":"2019-12-27T04:46:25","slug":"20191227-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191227-00\/?p=103271","title":{"rendered":"Controversial extension methods: <CODE>CastTo&lt;T&gt;<\/CODE> and <CODE>As&lt;T&gt;<\/CODE>"},"content":{"rendered":"<p>You&#8217;ve probably had to do this in C#. You get an object, you need to cast it to some type <code>T<\/code> and then fetch a property that is returned as an <code>object<\/code>, so you have to cast <i>that<\/i> to some other type <code>U<\/code>, so you can read the destination property.<\/p>\n<p>For example, you have a <code>ComboBoxItem<\/code>, and you put some extra data in the <code>Tag<\/code>.<\/p>\n<pre>void AddComboBoxItem(Thing thing)\r\n{\r\n    var item = new ComboBoxItem { Content = thing.Name, Tag = thing };\r\n    someComboBox.Items.Append(item);\r\n}\r\n\r\nvoid OnSelectionChanged(object sender, SelectionChangedEventArgs e)\r\n{\r\n    var thing = (Thing)((ComboBoxItem)((ComboBox)sender).SelectedItem)?.Tag;\r\n    ...\r\n}\r\n<\/pre>\n<p>In this case, when the selection changes, we ask the <code>ComboBox<\/code> for its currently-selected item, cast it to a <code>Combo\u00adBox\u00adItem<\/code>, then get the <code>Tag<\/code> from it, then cast the <code>Tag<\/code> to the <code>Thing<\/code> that we were after in the first place.<\/p>\n<p>In order to parse that expression, your eyes have to bounce back and forth because the casts are on the left, but the method calls and property accesses are on the right.<\/p>\n<pre>    \/\/             6           4           2       1         3          5\r\n    var thing = (Thing)((ComboBoxItem)((ComboBox)sender).SelectedItem)?.Tag;\r\n<\/pre>\n<p>You also have to pay attention to the parentheses, or what&#8217;s more likely to be the case, you simply trust that the parentheses are in the right place.<\/p>\n<p>Enter the controversial extension method <code>CastTo&lt;T&gt;<\/code>.<\/p>\n<pre>namespace ObjectExtensions\r\n{\r\n    static class ExtensionMethods\r\n    {\r\n        public static T CastTo&lt;T&gt;(this object o) =&gt; (T)o;\r\n    }\r\n}\r\n<\/pre>\n<p>With this extension method, you can write your code as a straightforward left-to-right sequence.<\/p>\n<pre>void OnSelectionChanged(object sender, SelectionChangedEventArgs e)\r\n{\r\n    var thing = sender.CastTo&lt;ComboBox&gt;().SelectedItem.CastTo&lt;ComboBoxItem&gt;()?.Tag.CastTo&lt;Thing&gt;();\r\n    ...\r\n}\r\n<\/pre>\n<p>You can break up the long line for readability, and the fact that there are no large spans of parentheses makes the line breaks easier to place.<\/p>\n<pre>void OnSelectionChanged(object sender, SelectionChangedEventArgs e)\r\n{\r\n    var thing = sender\r\n        .CastTo&lt;ComboBox&gt;()\r\n        .SelectedItem\r\n        .CastTo&lt;ComboBoxItem&gt;()\r\n        ?.Tag\r\n        .CastTo&lt;Thing&gt;();\r\n\r\n    ...\r\n}\r\n<\/pre>\n<p>Some people use the <code>as<\/code> operator instead of a cast, not because they actually care about the failure case (in which the result of the <code>as<\/code> is <code>null<\/code>), but because it lets them write things left-to-right.<\/p>\n<pre>void OnSelectionChanged(object sender, SelectionChangedEventArgs e)\r\n{\r\n    \/\/             1         2              3               4         5       6\r\n    var thing = ((sender as ComboBox).SelectedItem as ComboBoxItem)?.Tag as Thing\r\n    ...\r\n}\r\n<\/pre>\n<p>This lets you read from left to right, but you still have to mind your parentheses. It looks a little prettier, but it also <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170725-00\/?p=96676\"> makes debugging harder<\/a>.<\/p>\n<p>You can write a similar extension method for <code>as<\/code>.<\/p>\n<pre>namespace ObjectExtensions\r\n{\r\n    static class ExtensionMethods\r\n    {\r\n        public static T CastTo&lt;T&gt;(this object o) =&gt; (T)o;\r\n        public static T As&lt;T&gt;(this object o) where T : class =&gt; o as T;\r\n    }\r\n}\r\n<\/pre>\n<p>This lets you change the above to<\/p>\n<pre>void OnSelectionChanged(object sender, SelectionChangedEventArgs e)\r\n{\r\n    var thing = sender\r\n        .As&lt;ComboBox&gt;()\r\n        .SelectedItem\r\n        .As&lt;ComboBoxItem&gt;()\r\n        ?.Tag\r\n        .As&lt;Thing&gt;();\r\n    ...\r\n}\r\n<\/pre>\n<p>I suspect that like my crazy <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190328-00\/?p=102368\"> thread-switching tasks<\/a>, people are going to think either that this is a really cool trick, or it&#8217;s an offense against nature.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reduction in eye exercises.<\/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-103271","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Reduction in eye exercises.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103271","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=103271"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103271\/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=103271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}