{"id":55933,"date":"2010-04-04T13:34:00","date_gmt":"2010-04-04T13:34:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2010\/04\/04\/parallelextensionsextras-tour-1-linq-to-tasks\/"},"modified":"2010-04-04T13:34:00","modified_gmt":"2010-04-04T13:34:00","slug":"parallelextensionsextras-tour-1-linq-to-tasks","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/parallelextensionsextras-tour-1-linq-to-tasks\/","title":{"rendered":"ParallelExtensionsExtras Tour &#8211; #1 &#8211; LINQ to Tasks"},"content":{"rendered":"<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\"><em>(The full set of ParallelExtensionsExtras Tour posts is available&nbsp;<a href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2010\/04\/04\/9990342.aspx\">here<\/a>.)<\/em>&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The <\/font><a href=\"http:\/\/msdn.microsoft.com\/en-us\/netframework\/aa904594.aspx\"><font size=\"3\" face=\"Calibri\">.NET Framework developer center<\/font><\/a><font size=\"3\"><font face=\"Calibri\"> provides a concise description of Language Integrated Query (LINQ):<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoQuote\"><em><font size=\"3\"><font face=\"Calibri\">LINQ is a set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations. It extends C# and Visual Basic with native language syntax for queries and provides class libraries to take advantage of these capabilities.<\/p>\n<p><\/font><\/font><\/em><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">These &#8220;operations&#8221; are more of a pattern than anything else, in that there isn&rsquo;t just one implementation of them.<span>&nbsp; <\/span>Rather, any framework that wishes to follow the structure set forth by LINQ can do so, implementing the operators in a manner that befits the nature of the framework.<span>&nbsp; <\/span>There is a primary implementation of these LINQ operators against any IEnumerable&lt;T&gt; (an implementation typically referred to as <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb397919.aspx\">LINQ to Objects<\/a>), but that&rsquo;s just the beginning.<span>&nbsp; <\/span>There&rsquo;s a parallelized implementation of LINQ to Objects in the form of Parallel LINQ to Objects, or <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd460688(VS.100).aspx\">PLINQ<\/a>.<span>&nbsp; <\/span>There&rsquo;s an implementation that targets SQL Server databases, known as <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb386976(v=VS.90).aspx\">LINQ to SQL<\/a>.<span>&nbsp; <\/span>There&rsquo;s an implementation that targets IObservable&lt;T&gt; known as <a href=\"https:\/\/msdn.microsoft.com\/en-us\/devlabs\/ee794896.aspx\">Reactive Extensions<\/a>.<span>&nbsp; <\/span>And many more.<span>&nbsp; <\/span>What&rsquo;s more, the C# and Visual Basic language syntax for these queries targets the aforementioned pattern rather than a specific implementation of that pattern, and as a result, it works with most of these providers in an easily pluggable manner.<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><a href=\"https:\/\/code.msdn.microsoft.com\/ParExtSamples\"><font size=\"3\" face=\"Calibri\">ParallelExtensionsExtras<\/font><\/a><font size=\"3\"><font face=\"Calibri\"> includes an implementation of a subset of the LINQ operators.<span>&nbsp; <\/span>This implementation targets System.Threading.Tasks.Task instances rather than enumerables or observables or whatever other source.<span>&nbsp; <\/span>In doing so, it enables usage of the language syntax for writing asynchronous code, in very much the same manner that Reactive Extensions does, albeit in a much more limited form.<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Let&rsquo;s start by looking at a very simple query against enumerables:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">IEnumerable&lt;string&gt; result = from item in enumerable<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>select item.ToString();<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">The C# compiler compiles this query to the equivalent of the following:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">IEnumerable&lt;string&gt; result = enumerable.Select&lt;int,string&gt;(<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp; (int item) =&gt; return item.ToString());<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">This code utilizes the LINQ Select method, and specifically the following override:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static IEnumerable&lt;TResult&gt; Select&lt;TSource, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this IEnumerable&lt;TSource&gt; source, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TResult&gt; selector);<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">This is the specific implementation of the select pattern for IEnumerable&lt;T&gt;, but any type can be substituted in for it (for the &#8220;X&#8221; in the below signature):<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static <b>X<\/b>&lt;TResult&gt; Select&lt;TSource, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this <b>X<\/b>&lt;TSource&gt; source, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TResult&gt; selector);<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">As long as a type has an accessible method (or extension method) that fits this pattern, the C# compiler may bind to it.<span>&nbsp; <\/span>So, we can substitute &ldquo;Task&rdquo; for &ldquo;X&rdquo;, giving us:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static <strong>Task<\/strong>&lt;TResult&gt; Select&lt;TSource, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this <strong>Task<\/strong>&lt;TSource&gt; source, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TResult&gt; selector);<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Now we just need to figure out how to implement this method.<span>&nbsp; <\/span>Given a Task&lt;TSource&gt; source, we need to get its result of type TSource, run it through a selector function to produce a TResult, and a return a new Task&lt;TResult&gt; that will provide the resulting value.<span>&nbsp; <\/span>Ideally, we&rsquo;d do this in an asynchronous manner, such that the resulting Task&lt;TResult&gt; would represent the asynchronous processing of the selector function with the result of the input Task&lt;TSource&gt; once it had completed.<span>&nbsp; <\/span>As it turns out, this is trivial to do with Task&rsquo;s ContinueWith method:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static Task&lt;TResult&gt; Select&lt;TSource, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this Task&lt;TSource&gt; source, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TResult&gt; selector)<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">{<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>return <strong>source.ContinueWith(t =&gt; selector(t.Result));<\/p>\n<p><\/strong><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">}<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">By implementing just that one extension method, we can now successful write the following C# code:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">Task&lt;string&gt; result = from x in Task.Factory.StartNew(<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; () =&gt; ProduceInt())<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>select x.ToString();<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">That alone isn&rsquo;t all that interesting.<span>&nbsp; <\/span>What if I wanted to chain multiple tasks together, for example:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">Task&lt;string&gt; result = from x in Task.Factory.StartNew(<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; () =&gt; ProduceInt())<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>from y in Task.Factory.StartNew(<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;() =&gt; Process(x))<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>select y.ToString();<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Now I&rsquo;m looking to asynchronous execute ProduceInt() to give me an integral value <em>x<\/em>.<span>&nbsp; <\/span>Then I want to asynchronously process <em>x<\/em> and produce a new value <em>y<\/em>, at which point I want to asynchronously process <em>y<\/em> by getting its string representation, and I want a resulting Task&lt;string&gt; to represent that.<span>&nbsp; <\/span>This pattern of multiple from clauses is handled by the C# compiler with the SelectMany operator.<span>&nbsp; <\/span>Here is the relevant signature of SelectMany for enumerables:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static IEnumerable&lt;TResult&gt; SelectMany<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;TSource, TCollection, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this IEnumerable&lt;TSource&gt; source, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, IEnumerable&lt;TCollection&gt;&gt; collectionSelector, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TCollection, TResult&gt; resultSelector);<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Given a source, this method runs the collectionSelector function for each item in the source, producing an enumerable for each item.<span>&nbsp; <\/span>That item and its resulting enumerable are then provided to a resultSelector function, which produces the final result that&rsquo;s yielded as part of SelectMany&rsquo;s output enumerable.<span>&nbsp; <\/span>The same thing is possible for Task, again by substituting &ldquo;Task&rdquo; anywhere we see &ldquo;IEnumerable&rdquo;:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static <b>Task<\/b>&lt;TResult&gt; SelectMany<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;TSource, TCollection, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this <b>Task<\/b>&lt;TSource&gt; source, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, <b>Task<\/b>&lt;TCollection&gt;&gt; collectionSelector, <\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TCollection, TResult&gt; resultSelector);<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">This method is a bit more complicated to implement, but it is still just a few lines of code by taking advantage of ContinueWith:<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">public static Task&lt;TResult&gt; SelectMany<\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;TSource, TCollection, TResult&gt;(<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>this Task&lt;TSource&gt; source,<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, Task&lt;TCollection&gt;&gt; collectionSelector,<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Func&lt;TSource, TCollection, TResult&gt; resultSelector)<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">{<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>return source.ContinueWith(t =&gt;<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Task&lt;TCollection&gt; ct = collectionSelector(t.Result);<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>return ct.ContinueWith(_ =&gt; <\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resultSelector(t.Result, ct.Result));<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>}).Unwrap();<\/p>\n<p><\/font><\/p>\n<p class=\"Code\"><font face=\"Consolas\">}<\/p>\n<p><\/font><\/p>\n<p class=\"Code\">\n<p><font face=\"Consolas\">&nbsp;<\/font><\/p>\n<\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">First, we continue from the source to signal us when it&#8217;s completed.<span>&nbsp; <\/span>At that point, we run the collectionSelector with the source&rsquo;s result in order to produce the intermediate Task&lt;Collection&gt;.<span>&nbsp; <\/span>When that intermediate task has completed (which we again know by using ContinueWith), we run the result selector over the two previous results to produce the final value.<span>&nbsp; <\/span>Of course, this result of the second ContinueWith call (which produces a Task&lt;TResult&gt;) is being returned as a the result of the first ContinueWith call, such that the outer ContinueWith is actually returning a Task&lt;Task&lt;TResult&gt;&gt;.<span>&nbsp; <\/span>But SelectMany needs to return just a Task&lt;TResult&gt;.<span>&nbsp; <\/span>The Unwrap method provided by the Task Parallel Library handles this conversion, providing a Task&lt;TResult&gt; that asynchronously represents the combination of the outer and inner tasks from the Task&lt;Task&lt;TResult&gt;&gt;. With that in place, we can successfully write the desired query with two from clauses.<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">I&rsquo;ve omitted some details from these implementations, but you get the basic jist.<span>&nbsp; <\/span>The LinqToTasks.cs file in <\/font><a href=\"https:\/\/code.msdn.microsoft.com\/ParExtSamples\"><font size=\"3\" face=\"Calibri\">ParallelExtensionsExtras<\/font><\/a><font size=\"3\"><font face=\"Calibri\"> provides a set of more complete implementations, covering Select, SelectMany, Where, Join, GroupJoin, GroupBy, OrderBy, and more.<span>&nbsp; <\/span>How useful this LINQ implementation is in practice is arguable, but at the very least it provides for an interesting thought exercise as well as a set of examples for doing some complicated asynchronous logic with ContinueWith.<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Enjoy!<\/p>\n<p><\/font><\/font><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>(The full set of ParallelExtensionsExtras Tour posts is available&nbsp;here.)&nbsp; The .NET Framework developer center provides a concise description of Language Integrated Query (LINQ): LINQ is a set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations. It extends C# and Visual Basic with native language syntax for queries and provides [&hellip;]<\/p>\n","protected":false},"author":360,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7907,7911,7924,7912],"class_list":["post-55933","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4","tag-code-samples","tag-parallelextensionsextras","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>(The full set of ParallelExtensionsExtras Tour posts is available&nbsp;here.)&nbsp; The .NET Framework developer center provides a concise description of Language Integrated Query (LINQ): LINQ is a set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations. It extends C# and Visual Basic with native language syntax for queries and provides [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55933","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/360"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=55933"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55933\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=55933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=55933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=55933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}