{"id":8971,"date":"2021-10-21T19:02:55","date_gmt":"2021-10-21T19:02:55","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=8971"},"modified":"2021-10-21T19:02:55","modified_gmt":"2021-10-21T19:02:55","slug":"more-pattern-matching-in-c","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/more-pattern-matching-in-c\/","title":{"rendered":"More Pattern Matching in C#"},"content":{"rendered":"<p>A while back I wrote a post <a href=\"http:\/\/putridparrot.com\/blog\/c-8-0-enhancements-with-pattern-matching\/\" rel=\"noopener\" target=\"_blank\">C# 8.0 enhancements with pattern matching<\/a> which was very light on the subject. Let&#8217;s look a little more in depth at options for pattern matching.<\/p>\n<p><strong>is\/as in pattern matching syntax<\/strong><\/p>\n<p>Often (if you&#8217;ve been writing C# for a while) you&#8217;ll used to writing code like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar person = o as Person;\r\nif (person != null)\r\n{\r\n   Console.WriteLine(person.FirstName);\r\n}\r\n<\/pre>\n<p>i.e. we have an object <em>o<\/em> which we don&#8217;t know the type of, so we use <em>as<\/em> to convert this to a Person type or null if it&#8217;s not of that type. <\/p>\n<p>This can be replaced with a slightly more concise syntax (and what&#8217;s known as the <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#declaration-and-type-patterns\" rel=\"noopener\" target=\"_blank\">declaration pattern<\/a>).<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nif (o is Person person)\r\n{\r\n  Console.WriteLine(person.FirstName);\r\n}\r\n<\/pre>\n<p><strong>Null checks<\/strong><\/p>\n<p>This is a pattern known as a <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#constant-pattern\" rel=\"noopener\" target=\"_blank\">constant pattern<\/a><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nif (o is null)\r\n{\r\n  Console.WriteLine(&quot;Is null&quot;);\r\n}\r\n<\/pre>\n<p>Along with a <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#logical-patterns\" rel=\"noopener\" target=\"_blank\">logical pattern<\/a> using <em>not<\/em> we can also write <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nif (o is not null)\r\n{\r\n  Console.WriteLine(&quot;Is not null&quot;);\r\n}\r\n<\/pre>\n<p>We can also use this pattern with types, for example<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nif (o is not (string or null))\r\n{\r\n  Console.WriteLine(&quot;Is NOT string or null&quot;);\r\n}\r\n\r\n&lt;strong&gt;Pattern matching when values match a criteria&lt;\/strong&gt;\r\n\r\nIf we extend the above Pattern Matching to not just check the type is a Person but also that the Age property is greater than 4, so we can now replace\r\n\r\n&#x5B;code language=&quot;csharp&quot;]\r\nif (o is Person p &amp;&amp; p.Age &gt; 4)\r\n{\r\n  Console.WriteLine($&quot;Older than 4 {p.FirstName}&quot;);\r\n}\r\n<\/pre>\n<p>with the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nif (o is Person { Age: &gt; 4 } p)\r\n{\r\n   Console.WriteLine($&quot;Older than 4 {p.FirstName}&quot;);\r\n}\r\n<\/pre>\n<p>In the above we&#8217;re using a <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#property-pattern\" rel=\"noopener\" target=\"_blank\">property pattern<\/a>.<\/p>\n<p><strong>Switch patterns matching<\/strong><\/p>\n<p>Exhaustive switches can be used to match types using switch statements, for example<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar result = o switch\r\n{\r\n  string s =&gt; $&quot;String {s}&quot;,\r\n  Person p =&gt; $&quot;Person {p.FirstName}&quot;,\r\n  _ =&gt; throw new ArgumentException(&quot;Unhandled type&quot;)\r\n};\r\n<\/pre>\n<p>Note the use of the _ (discard) ensuring this is an exhaustive switch.<\/p>\n<p>Better still we can also use other features of pattern matching in the switch like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar result = o switch\r\n{\r\n  string s =&gt; $&quot;String {s}&quot;,\r\n  Person { Age: &gt; 4} p =&gt; $&quot;Person {p.FirstName} &gt; 4&quot;,\r\n  Person p =&gt; $&quot;Person {p.FirstName}&quot;,\r\n  null =&gt; &quot;In Null&quot;,\r\n  _ =&gt; throw new ArgumentException(&quot;Unhandled type&quot;)\r\n};\r\n<\/pre>\n<p>In the above we&#8217;re switching based upon type and also matching values.<\/p>\n<p>We can also use <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#relational-patterns\" rel=\"noopener\" target=\"_blank\">relational patterns<\/a>, in this example we&#8217;ll assume <em>o<\/em> is an int<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar result = o switch\r\n{\r\n  1 or 2 =&gt; &quot;One or Two&quot;,\r\n  &gt; 2 and &lt; 4 =&gt; &quot;Mid&quot;,\r\n  &gt;= 4 and &lt; 6 =&gt; &quot;High&quot;,\r\n  6 =&gt; &quot;Six&quot;,\r\n  _ =&gt; &quot;Other&quot;\r\n};\r\n<\/pre>\n<p>Before we leave the <em>switch<\/em> statement we can also match against types using the &#8220;standard&#8221; switch syntax, i.e.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nswitch (o)\r\n{\r\n  case string s:\r\n    Console.WriteLine(s);\r\n    break;\r\n  case Person p:\r\n    Console.WriteLine(p.FirstName);\r\n    break;\r\n}\r\n<\/pre>\n<p><strong>Tuples<\/strong><\/p>\n<p>Pattern matching also allows us to match against tuples and use the discard to ignore parts we&#8217;re not interested in, for example<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar result = o switch\r\n{\r\n  (1, _) =&gt; &quot;First One&quot;,\r\n  (_, 0) =&gt; &quot;Second Zero&quot;,\r\n  _ =&gt; &quot;Other&quot;\r\n};\r\n<\/pre>\n<p><strong>Creating new variables from patterns<\/strong><\/p>\n<p>We can also use the <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#var-pattern\" rel=\"noopener\" target=\"_blank\">var pattern<\/a> to assign values from the patterns<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar result = o switch\r\n{\r\n  var (a, b) when a &lt; b =&gt; new Tuple&lt;string, int, int&gt;(&quot;First less than second&quot;, a, b),\r\n  var (a, b) when a &gt; b =&gt; new Tuple&lt;string, int, int&gt;(&quot;Second greater than first&quot;, a, b),\r\n  var (a, b) =&gt; new Tuple&lt;string, int, int&gt;(&quot;Equals&quot;, a, b)\r\n};\r\n<\/pre>\n<p>In this example we&#8217;re deconstructing a tuple and assigning to some new value (in this case an extended Tuple, just because I couldn&#8217;t think of a better example &#8211; check the documentation link above for a better example).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A while back I wrote a post C# 8.0 enhancements with pattern matching which was very light on the subject. Let&#8217;s look a little more in depth at options for pattern matching. is\/as in pattern matching syntax Often (if you&#8217;ve been writing C# for a while) you&#8217;ll used to writing code like this var person [&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-8971","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\/8971","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=8971"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8971\/revisions"}],"predecessor-version":[{"id":8978,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8971\/revisions\/8978"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=8971"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=8971"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=8971"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}