{"id":10341,"date":"2023-12-10T16:13:45","date_gmt":"2023-12-10T16:13:45","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=10341"},"modified":"2023-12-10T16:13:45","modified_gmt":"2023-12-10T16:13:45","slug":"collection-expressions-in-c-12","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/collection-expressions-in-c-12\/","title":{"rendered":"Collection Expressions in C# 12"},"content":{"rendered":"<p>C# 12 includes something called <em>Collection Expressions<\/em>. These offer more generic way to create our collections from array-like syntax.<\/p>\n<p>Let&#8217;s look first at the old style creation of an array of integers<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar array = new &#x5B;] { 1, 2, 3 };\r\n<\/pre>\n<p>This is simple enough <em>array<\/em> is of type <em>int[]?<\/em>. This way of creation arrays is not going away, but what if we want to change the <em>array<\/em> to a different collection then we end up using collection initializers like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar list = new List&lt;int&gt; { 1, 2, 3 };\r\n<\/pre>\n<p>There&#8217;s nothing much wrong with this, but essentially we&#8217;re sort of doing the same thing, just with different syntax.<\/p>\n<p>Collection expressions now allow us to use syntax such as (below) to create our collection regardless of type<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nint&#x5B;] array = &#x5B;1, 2, 3 ];\r\nList&lt;int&gt; list = &#x5B;1, 2, 3 ];\r\n<\/pre>\n<p>On the surface this may not seem a big deal, but imagine you&#8217;ve a class that accepts an <em>int[]<\/em> and maybe you change the type to a <em>List<int><\/em>, passing the values via the collection expression [] syntax means that part of your code remains unchanged, it just remains as [1, 2, 3].<\/p>\n<p>Along with this we get to use the spread operator .. for example<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nList&lt;int&gt; list = &#x5B;1, 2, 3 ];\r\nint&#x5B;] array = &#x5B;.. list];\r\n<\/pre>\n<p>In this example we&#8217;ve created a list then basically copied the items to the array, but a spread operator can be used to concatenate values (or collections), such as<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nint&#x5B;] array = &#x5B;-3, -2, -1, 0, .. list];\r\n<\/pre>\n<p><strong>Creating your own collections to use collection expressions<\/strong><\/p>\n<p>For many of the original types, such as List&lt;T&gt; the collection expression code is built in. But newer collections and, if we want, our own collection can take advantage of this syntax by following a minimal set of rules.<\/p>\n<p>All we need to do is create our collection type and add the CollectionBuilderAttribute to it like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;CollectionBuilder(typeof(MyCollection), nameof(MyCollection.Create))]\r\npublic class MyCollection&lt;T&gt;\r\n{\r\n   \/\/ our code\r\n}\r\n<\/pre>\n<p>Now this is not going to work, the typeof expects a non-generic type, so we create a simple non-generic version of this class to handle the creation of the generic version. Also notice the CollectionBuilder expects the name of the method to call and expects a method that takes a single parameter of type <em>ReadOnlySpan<\/em> and returns the collection type, now initialized, like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class MyCollection\r\n{\r\n  public static MyCollection&lt;T&gt; Create&lt;T&gt;(ReadOnlySpan&lt;T&gt; items)\r\n  {\r\n     \/\/ returns a MyCollection&lt;T&gt;\r\n  }\r\n}\r\n<\/pre>\n<p>Let&#8217;s look at potential bare minimum implementation of this collection type which can be used with the collection expression syntax. Notice we will also need to implement IEnumerable and\/or IEnumerable&lt;T&gt; <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;CollectionBuilder(typeof(MyCollection), nameof(MyCollection.Create))]\r\npublic class MyCollection&lt;T&gt; : IEnumerable&lt;T&gt;\r\n{\r\n  public static readonly MyCollection&lt;T&gt; Empty = new(Array.Empty&lt;T&gt;());\r\n\r\n  private readonly List&lt;T&gt; _innerCollection;\r\n\r\n  internal MyCollection(T&#x5B;]? items)\r\n  {\r\n    _innerCollection = items == null ? new List&lt;T&gt;() : &#x5B;..items];\r\n  }\r\n\r\n  public T this&#x5B;int index] =&gt; _innerCollection&#x5B;index];\r\n  public IEnumerator&lt;T&gt; GetEnumerator() =&gt; _innerCollection.GetEnumerator();\r\n  IEnumerator IEnumerable.GetEnumerator() =&gt; _innerCollection.GetEnumerator();\r\n}\r\n\r\npublic class MyCollection\r\n{\r\n  public static MyCollection&lt;T&gt; Create&lt;T&gt;(ReadOnlySpan&lt;T&gt; items)\r\n  {\r\n    return items.IsEmpty ? \r\n      MyCollection&lt;T&gt;.Empty : \r\n      new MyCollection&lt;T&gt;(items.ToArray());\r\n  }\r\n}\r\n<\/pre>\n<p>Ofcourse this is a silly example as we&#8217;re not adding anything that the inner <em>List&lt;T&gt;<\/em> cannot supply, but you get the idea. Now we can use the collection expression syntax on our new collection type<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nMyCollection&lt;int&gt; collection = &#x5B;1, 2, 6, 7];\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>C# 12 includes something called Collection Expressions. These offer more generic way to create our collections from array-like syntax. Let&#8217;s look first at the old style creation of an array of integers var array = new &#x5B;] { 1, 2, 3 }; This is simple enough array is of type int[]?. This way of creation [&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-10341","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\/10341","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=10341"}],"version-history":[{"count":2,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10341\/revisions"}],"predecessor-version":[{"id":10343,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10341\/revisions\/10343"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=10341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=10341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=10341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}