{"id":1060,"date":"2011-01-05T00:00:00","date_gmt":"2011-01-05T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/linq-lycanthropy-transformations-into-linq\/"},"modified":"2021-05-17T18:36:27","modified_gmt":"2021-05-17T18:36:27","slug":"linq-lycanthropy-transformations-into-linq","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/linq-lycanthropy-transformations-into-linq\/","title":{"rendered":"LINQ Lycanthropy: Transformations into LINQ"},"content":{"rendered":"<div id=\"pretty\">\n<h2>Contents<\/h2>\n<ul>\n<li><a href=\"#first\">A Brief LINQ Introduction<\/a>\n<ul>\n<li><a href=\"#second\">LINQ Operations<\/a><\/li>\n<li><a href=\"#third\">LINQ Providers<\/a><\/li>\n<li><a href=\"#fourth\">The Two Faces of LINQ<\/a><\/li>\n<li><a href=\"#fifth\">LINQ to Objects<\/a><\/li>\n<li><a href=\"#sixth\">Declarative vs. Imperative Design<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#seventh\">The Transformation Target<\/a>\n<ul>\n<li><a href=\"#eighth\">First Pass: Pseudo-Code<\/a><\/li>\n<li><a href=\"#ninth\">Second Pass: Imperative Code<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#tenth\">The Journey to LINQ<\/a>\n<ul>\n<li><a href=\"#eleventh\">What Can You Gain From LINQ?<\/a><\/li>\n<li><a href=\"#twelveth\">Conversion Stage A<\/a><\/li>\n<li><a href=\"#thirteenth\">Conversion Stage B<\/a><\/li>\n<li><a href=\"#fourteenth\">Conversion Stage C<\/a><\/li>\n<li><a href=\"#fifteenth\">Conversion Stage D<\/a><\/li>\n<li><a href=\"#sixteenth\">Conversion Stage E<\/a><\/li>\n<li><a href=\"#seventeenth\">Final Conversion<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#eighteenth\">Tools to Help Learn LINQ<\/a>\n<ul>\n<li><a href=\"#nineteenth\">Resharper Converts Your Code to LINQ<\/a><\/li>\n<li><a href=\"#twentieth\">LINQPad Shows the SQL generated by your LINQ<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#twentyfirst\">Conclusion<\/a><\/li>\n<li><a href=\"#twentysecond\">Footnotes<\/a><\/li>\n<\/ul>\n<div class=\"float-right gloss\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-warewolf.jpg\" alt=\"1210-warewolf.jpg\" \/><br \/>\n A SQL Server Database is surprised by an <br \/>\n unexpected LINQ query<\/div>\n<p class=\"start\">Much has been written about the benefits of LINQ, and on the features of LINQ. Either focus is valid, to be sure, but to someone new to the technology, LINQ can still present quite a formidable initiation. But LINQ is one of those rare commodities that can both be <i>learned incrementally<\/i> and <i>applied incrementally<\/i>. Consider, for example, learning C#. You have to understand many different concepts and learn a good part of the language&#8217;s syntax before you can even write the quintessential &#8220;Hello, World!&#8221; program. With LINQ, on the other hand, you can learn just a little bit about something you need to use <i>now<\/i> and then immediately apply just that little bit.<a href=\"#footnote1\">[1]<\/a> In this article I want to illustrate this incremental nature of learning LINQ by showing how to convert conventional code to LINQ code.<a href=\"#footnote2\">[2]<\/a><\/p>\n<h2 id=\"first\">A Brief LINQ Introduction<\/h2>\n<p>LINQ, short for <b>L<\/b>anguage <b>In<\/b>tegrated <b>Q<\/b>uery, was introduced with the .NET 3.5 framework. MSDN describes its purpose succinctly:<\/p>\n<p><i>&#8220;Traditionally, queries against data are expressed as simple strings without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query language for each type of data source: SQL databases, XML documents, various Web services, and so on. LINQ makes a query a first-class language construct in C# and Visual Basic. You write queries against strongly typed collections of objects by using language keywords and familiar operators.&#8221;<\/i><\/p>\n<p>The main advantages of using LINQ are that:<\/p>\n<ul>\n<li>Code is more concise and readable, especially when using multiple filters.<\/li>\n<li>You can filter, order, and group results with little coding.<\/li>\n<li>You can easily port a LINQ query from one data source to another with little or no modification.<\/li>\n<\/ul>\n<h3 id=\"second\">LINQ Operations<\/h3>\n<p>With LINQ, you can filter data to retrieve a subset, transform a sequence of elements to new forms, perform aggregate operations (average, max, count, etc.), combine data from multiple sources, and more. Table 1 summarizes these operations:<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael1.jpg\" alt=\"1210-Michael1.jpg\" \/><\/p>\n<p class=\"caption\">Table 1 LINQ Operations<\/p>\n<h3 id=\"third\">LINQ Providers<\/h3>\n<p>Traditionally, most of the operations above are done on a database. While LINQ of course supports the database domain, the power of LINQ is that it can be used in the very same fashion when accessing data from a variety of domains, via appropriate <i>LINQ providers<\/i>. The LINQ providers supplied &#8220;out of the box&#8221; from Microsoft include:<\/p>\n<ul>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb386976.aspx\">SQL Server databases<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb387098.aspx\">XML documents<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb386977.aspx\">ADO.NET datasets<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb397919.aspx\">.NET objects<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb386964.aspx\">Entity Framework elements<\/a><\/li>\n<\/ul>\n<p>There are a plethora of others created by independent software developers. This list comes mostly from Charlie Calvert&#8217;s blog entry <a href=\"http:\/\/blogs.msdn.com\/b\/charlie\/archive\/2008\/02\/28\/link-to-everything-a-list-of-linq-providers.aspx\">Link to Everything: A List of LINQ Providers<\/a> with additional entries from Wikipedia&#8217;s <a href=\"http:\/\/en.wikipedia.org\/wiki\/Language_Integrated_Query#Other_providers\">list of LINQ providers<\/a> (each source supplies hyperlinks for each provider in their respective list):<\/p>\n<div>\n<ul>\n<li>Active Directory<\/li>\n<li>Amazon<\/li>\n<li>Bindable Sources (SyncLINQ)<\/li>\n<li>C# project<\/li>\n<li>Continuous Data (CLinq)<\/li>\n<li>CRM<\/li>\n<li>CSV<\/li>\n<li>Excel<\/li>\n<li>Expressions (MetaLinq)<\/li>\n<li>Flickr<\/li>\n<li>Geo (Geospatial Data)<\/li>\n<li>Google<\/li>\n<li>Indexes (LINQ &amp; i40)<\/li>\n<li>IQueryable<\/li>\n<li>JavaScript<\/li>\n<li>JSON<\/li>\n<li>LDAP<\/li>\n<li>LLBLGen Pro<\/li>\n<li>Lucene<\/li>\n<li>MAPI<\/li>\n<li>Metaweb<\/li>\n<li>MySQL, Oracle, PostgreSql<\/li>\n<li>NCover<\/li>\n<li>NHibernate<\/li>\n<li>Opf3<\/li>\n<li>Parallel (PLINQ)<\/li>\n<li>RDF Files<\/li>\n<li>Sharepoint<\/li>\n<li>SimpleDB<\/li>\n<li>Streams<\/li>\n<li>System Search<\/li>\n<li>Twitter<\/li>\n<li>WebQueries<\/li>\n<li>Wikipedia<\/li>\n<li>WIQL<\/li>\n<li>WMI<\/li>\n<li>XSD<\/li>\n<li>XtraGrid<\/li>\n<\/ul>\n<\/div>\n<h3 id=\"fourth\">The Two Faces of LINQ<\/h3>\n<p>One of the first points of confusion about learning LINQ is that it looks like two different languages. Rather, it is a single language with two different syntaxes: <i>query syntax<\/i> and <i>method syntax<\/i>. Query syntax looks much like a SQL query though with the clauses in a different order. The <b>from &#8230; where &#8230; orderby &#8230; select<\/b> sequence is the canonical example of query syntax:<\/p>\n<pre class=\"lang:c# theme:vs2012\">var names = new[] { \"Tom\", \"Dick\", \"Harry\", \"Mary\", \"Jay\" };  IEnumerable&lt;string&gt; query =\r\n\u00a0\u00a0 from\u00a0\u00a0\u00a0\u00a0\u00a0 n in names\r\n\u00a0\u00a0 where\u00a0\u00a0\u00a0\u00a0 n.Contains (\"a\")\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Filter\r\n\u00a0\u00a0 orderby\u00a0\u00a0 n.Length\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Sort\r\n\u00a0\u00a0 select\u00a0\u00a0\u00a0 n.ToUpper();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Translate\r\n<\/pre>\n<p>Here is the identical LINQ statement written with method syntax. This is also called <i>lambda syntax<\/i> because these LINQ extension methods take a lambda expression<a href=\"#footnote3\">[3]<\/a> as an argument.<\/p>\n<pre class=\"lang:c# theme:vs2012\">var names = new[] { \"Tom\", \"Dick\", \"Harry\", \"Mary\", \"Jay\" };  IEnumerable&lt;string&gt; query = names\r\n\u00a0\u00a0 .Where\u00a0\u00a0 (n =&gt; n.Contains (\"a\")) \/\/ Filter\r\n\u00a0\u00a0 .OrderBy (n =&gt; n.Length)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Sort\r\n\u00a0\u00a0 .Select\u00a0 (n =&gt; n.ToUpper());\u00a0\u00a0\u00a0\u00a0 \/\/ Translate\r\n<\/pre>\n<p>The two types of syntax available for LINQ queries are exactly equivalent (where they overlap) so you can chose whichever you prefer. The performance question is moot; Their performance is the same because the first step of compilation will convert expressions written in either query syntax into lambda syntax. Depending on the operation, either syntax could produce code that is significantly shorter and clearer:; and you can even mix the two syntaxes if you like! The lambda syntax is much richer, particularly in C#, so if you start with query syntax, but then need an operator that is only available in lambda syntax, you can apply that as well. MSDN&#8217;s <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb882642.aspx\">Query Expression Syntax for Standard Query Operators<\/a> shows the subset of methods that may be invoked in query syntax in both C# and Visual Basic. Another useful reference is Brad Vincent&#8217;s <a href=\"http:\/\/weblogs.asp.net\/bradvincent\/archive\/2008\/11\/01\/linq-cheat-sheet.aspx\">dual syntax cross-reference<\/a> that shows how to write expressions in both query syntax and in lambda syntax side by side. Notice in the code that follows that I have mostly, but not exclusively, used method syntax.<\/p>\n<h3 id=\"fifth\">LINQ to Objects<\/h3>\n<p>This article focuses on LINQ to Objects for two reasons: <i>ease of use<\/i> and <i>universality<\/i>.<\/p>\n<p>In this context, any C# or Visual Basic object that implements the generic IEnumerable&lt;T&gt; interface may be manipulated with LINQ: collections, arrays, lists, dictionaries, or your own user-defined types. This covers a vast spectrum of the data types that involve sets of data-even more than you might think at first glance-because some types that are not IEnumerable&lt;T&gt; are convertible to types that are.<\/p>\n<p>Whichever LINQ provider is most appropriate for your situation, you have to provide additional information about your data so that LINQ may properly understand its structure. Say, for example you wish to use LINQ to SQL to process data from a database. You need to use the Object Relational Designer in Visual Studio (or the SqlMetal command line utility) to specify the tables and fields you plan to use. Once that is done you can then specify tables and field names, with the full support of strong-typing and Intellisense from Visual Studio. LINQ to Objects still has the same prerequisite but requires no additional work on your part. The reason is obvious: if you have objects you wish to manipulate, their structure is-by definition-already known!<\/p>\n<h3 id=\"sixth\">Declarative vs. Imperative Design<\/h3>\n<p>To quote MSDN again:<\/p>\n<p><i>&#8220;In a basic sense, LINQ to Objects represents a new approach to collections. In the old way, you had to write complex <b>foreach<\/b> loops that specified how to retrieve data from a collection. In the LINQ approach, you write declarative code that describes what you want to retrieve.&#8221;<\/i><\/p>\n<p>This is a remarkable achievement: it adds a layer of abstraction in your code where you can now describe <i>what<\/i> you want rather than <i>how<\/i> to go about it. Higher levels of abstraction lead to easier to read-and therefore more maintainable-code. Think of assembly language compared to C#, for example.<\/p>\n<p>Conventional C# code is imperative. You enumerate specific steps for arriving at a goal. With LINQ you can specify what you want to attain without having to specify the detailed steps. The book <a href=\"http:\/\/www.informit.com\/store\/product.aspx?isbn=0321564162\">Essential LINQ<\/a><span class=\"MsoHyperlink\">,<\/span> by Charlie Calvert and Dinesh Kulkarni, provides a great discussion of declarative vs. imperative code. The relevant section of the book is even available online at <a href=\"http:\/\/www.informit.com\/articles\/article.aspx?p=1330154&amp;seqNum=4\">Declarative: Not How, But What<\/a>.<\/p>\n<h2 id=\"seventh\">The Transformation Target<\/h2>\n<p>I mentioned that LINQ is a technology that may be incorporated into your environment in an incremental basis. In the remainder of this article I walk through an example where I do just that. The code comes straight out of an application called HostSwitcher that I built and discussed at length in my recent articles, <a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/creating-tray-applications-in-.net-a-practical-guide\/\">Creating Tray Applications in .NET: A Practical Guide<\/a> and <a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/linq-secrets-revealed-chaining-and-debugging\/#fourteenth\">LINQ Secrets Revealed: Chaining and Debugging<\/a>. In a nutshell, HostSwitcher lets you re-route entries in your hosts file with a single click on the context menu attached to its icon in the system tray. The application is heavily LINQ-centric. You can download both the source code and a prepackaged installer for the application from the first article. Here I will just show a portion of the code, focusing on the CreateMap method from the HostManager class.<\/p>\n<h3 id=\"eighth\">First Pass: Pseudo-Code<\/h3>\n<p>The CreateMap method converts the hosts file into a data dictionary. There are just three steps:<\/p>\n<p><b>(1) Decorate each hosts file line with details of its referenced project and server group, if present, discarding any lines that do not include such references.<\/b><\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael2.jpg\" alt=\"1210-Michael2.jpg\" \/><\/p>\n<p class=\"caption\">Figure 1 Host file lines decorated with project and server groups from their meta-comments<\/p>\n<p>This visualization of the data plainly reveals the syntax introduced to specify projects and server groups embedded within trailing comments in the hosts file.<\/p>\n<p><b>(2) Create a dictionary entry for each project (unless one already exists), where the dictionary key is the project name and the dictionary value is a list of server groups associated with that project.<\/b><\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael3.jpg\" alt=\"1210-Michael3.jpg\" \/><\/p>\n<p class=\"caption\">Figure 2 Dictionary generated from the hosts file data but sans counts<\/p>\n<p>Here I include each server group just once even if it appears on multiple host lines. The goal of this step is to define the hierarchy between the project groups and the server groups independently of the number of times they occur.<\/p>\n<p><b>(3) For each server group in each project, decorate it with a count of enabled and disabled lines.<\/b><\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael4.jpg\" alt=\"1210-Michael4.jpg\" \/><\/p>\n<p class=\"caption\">Figure 3 Dictionary with the count fields populated<\/p>\n<p>In this final step, I now turn my attention to the repeated entries for each server group. Looking back at the first step, observe that some host lines actually have two comment markers, one at the start of the line commenting out the entire entry and a second in the middle that redundantly comments out the meta-notation used by HostSwitcher. Thus, by adding or removing a comment marker at the <i>start<\/i> of a line you can enable or disable the host entry without uncommenting the meta-comment specifying the project and server group.<\/p>\n<h3 id=\"ninth\">Second Pass: Imperative Code<\/h3>\n<p>The input to the CreateMap method is the contents of the system hosts file stored in a list; the output is a map between project names and server groups:<\/p>\n<pre class=\"lang:c# theme:vs2012\">List&lt;string&gt; hostFileData;  Dictionary&lt;string, List&lt;ServerGroup&gt;&gt; projectDict;\r\n<\/pre>\n<p>Converting the pseudo-code above to imperative code is straightforward. Here again are the three steps:<\/p>\n<p><strong>(1) Decorate each hosts file line with details of its referenced project and server group, if present, discarding any lines that do not include such references.<\/strong><\/p>\n<p>A regular expression determines whether a line contains a project and server group. Ones that do are added to the activeHostsFileData collection along with the associated project and the server group.<\/p>\n<pre class=\"lang:c# theme:vs2012\">string HostsCommentMarker = \"#\";  string FilteringPattern = HostsCommentMarker + @\"\\s*\\[([^\/]+)\/([^]]+)\\]\";\r\nRegex FilteringRegex = new Regex(FilteringPattern);\r\n\r\nvar activeHostsFileData = new List&lt;HostDetail&gt;();\r\nforeach (var line in hostFileData)\r\n{\r\n\u00a0\u00a0\u00a0 var m = FilteringRegex.Match(line);\r\n\u00a0\u00a0\u00a0 if (m.Success)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 activeHostsFileData.Add(new HostDetail\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Line = line,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Project = m.Groups[ProjectSubGroupIndex].ToString().Trim(),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ServerGroupName = m.Groups[ServerGroupSubGroupIndex].ToString().Trim()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n<\/pre>\n<p><b>(2) Create a dictionary entry for each project (unless one already exists), where the dictionary key is the project name and the dictionary value is a list of server groups associated with that project.<\/b><\/p>\n<p>Here I take into account that there may be multiple lines in the host file specifying the same server group and only add it to the list if it does not already exist.<\/p>\n<pre class=\"lang:c# theme:vs2012\">projectDict.Clear();\r\nforeach (var item in activeHostsFileData)\r\n{\r\n\u00a0\u00a0\u00a0 if (!projectDict.ContainsKey(item.Project)) \r\n\u00a0\u00a0\u00a0 { projectDict[item.Project] = new List&lt;ServerGroup&gt;(); }\r\n\u00a0\u00a0\u00a0 var serverGroups = projectDict[item.Project];\r\n\r\n\u00a0\u00a0\u00a0 bool groupAlreadyPresent = false;\r\n\u00a0\u00a0\u00a0 foreach (var serverGroup in serverGroups)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (serverGroup.Name.Equals(item.ServerGroupName))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { groupAlreadyPresent = true; }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 if (!groupAlreadyPresent)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serverGroups.Add(new ServerGroup { Name = item.ServerGroupName });\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n<\/pre>\n<p><b>(3) For each server group in each project, decorate it with a count of enabled and a count of disabled lines.<\/b><\/p>\n<p>This triply nested loop iterates through the projects then through the server groups in the dictionary created in step 2 in order to update each such server group. The innermost loop iterates through the collection from step 1 checking for whether each line is commented (disabled) or uncommented (enabled).<\/p>\n<pre class=\"lang:c# theme:vs2012\">foreach (var project in projectDict.Keys)\r\n{\r\n\u00a0\u00a0\u00a0 foreach (var serverGroup in projectDict[project])\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach (var item in activeHostsFileData)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (item.Project.Equals(project) &amp;&amp;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 item.ServerGroupName.Equals(serverGroup.Name))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (!IsCommented(item.Line)) { serverGroup.EnabledCount++; }\r\n\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (IsCommented(item.Line)) { serverGroup.DisabledCount++; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n<\/pre>\n<h2 id=\"tenth\">The Journey to LINQ<\/h2>\n<p>The code archive accompanying this article includes a series of files with the .linq extension, indicating they are LINQPad files (rather than Visual Studio files). LINQPad is a great sandbox and lightweight IDE for experimenting and exploring your code, making it an ideal accompaniment here. [4]<\/p>\n<h3 id=\"eleventh\">What Can You Gain From LINQ?<\/h3>\n<p>The code above resides in HostSwitcher-initial.linq. There is a succession of file suffixes (A through E) that take the above code from pure imperative code to pure LINQ code. The final, completely LINQ version resides in HostSwitcher-final.linq. Table 2 attempts to show the improvement quantitatively. The second column shows the progress, going from 0% LINQ to 100%. The <b>description<\/b> column summarizes the changes from the preceding file. The <b>lines of code<\/b> is an imprecise measure of code complexity, yet reducing the line count in half certainly supports the conclusion that LINQ produces more concise code in this example. The <b>loop count<\/b> column is another simple measure of complexity. I use an abbreviated notation to show the number of singly-, doubly-, and triply-nested loops in the file. Again, the general trend scanning down the table is toward lower complexity. The final two columns indicate the number of supporting data classes and methods used; I include those here to show that you sometimes have to take a step back to move forward (i.e. B and C actually show increased complexity by that measure).<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael5.jpg\" alt=\"1210-Michael5.jpg\" \/><\/p>\n<p class=\"caption\">Table 2 Code Improvement due to &#8220;LINQ-ification&#8221;<\/p>\n<p>Subsequent sections provide guidance on how I transformed this code to LINQ step by step.<\/p>\n<h3 id=\"twelveth\">Conversion Stage A<\/h3>\n<p>The most obvious place to start to think about applying LINQ is the triply-nested loop in step 3. Instead of iterating through the collection of tagged lines, start with the collection itself (activeHostsFileData). Then consider what you want to do to it: in this case, restrict it to the lines for the current project and server group then see how many are commented and uncommented. The second part of that is just two further restrictions to the same common base collection. The loop plus three conditionals-certainly a chunk of code that is non-trivial-is replaced by essentially two straightforward assignment statements. (The third line could be incorporated in the other two but it is pulled out separately to avoid duplication.) This is the code in HostSwitcher-A.linq:<\/p>\n<pre class=\"lang:c# theme:vs2012\">foreach (var project in projectDict.Keys)\r\n{\r\n\u00a0\u00a0\u00a0 foreach (var serverGroup in projectDict[project])\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var serverGroupInHostsFile = activeHostsFileData\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Where(item =&gt; item.Project.Equals(project) \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &amp;&amp; item.ServerGroupName.Equals(serverGroup.Name));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serverGroup.EnabledCount = serverGroupInHostsFile\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Where(item =&gt; !IsCommented(item.Line)).Count();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serverGroup.DisabledCount = serverGroupInHostsFile\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Where(item =&gt; IsCommented(item.Line)).Count();\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n<\/pre>\n<h3 id=\"thirteenth\">Conversion Stage B<\/h3>\n<p>Candidate code for converting to LINQ usually involves a loop. But the code you just examined still has two more loops. So how would you apply LINQ conversion to eliminate the remaining two loops? Always start with the collection-projectDict in this case. What the two loops are really doing is operating on all the server groups in all the projects. LINQ has a special operator to flatten a two-level organization just like that into a single level. That is, we can use SelectMany to just get all the server groups obviating the need for the two loops. projectDict.Keys provides a list of all the projects. Each corresponding value is a list of the associated server groups. Thus you can say this&#8230;<\/p>\n<pre>projectDict.Keys.SelectMany(project =&gt; projectDict[project])<\/pre>\n<p>&#8230;to get a flat list of all the server groups. From this collection you next want to apply the same bit of code you just did in the previous section inside the double loop. It is cumbersome to try to massage a block of code inside a LINQ chain so just put the guts of that code into a separate method:<\/p>\n<pre class=\"lang:c# theme:vs2012\">private void Tally(List&lt;HostDetail&gt; activeHostsFileData, ServerGroup serverGroup)  {\r\n\u00a0\u00a0\u00a0 var serverGroupInHostsFile = activeHostsFileData\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Where(item =&gt; item.Project.Equals(serverGroup.Project)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &amp;&amp; item.ServerGroupName.Equals(serverGroup.Name));\r\n\u00a0\u00a0\u00a0 serverGroup.EnabledCount = serverGroupInHostsFile\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Where(item =&gt; !IsCommented(item.Line)).Count();\r\n\u00a0\u00a0\u00a0 serverGroup.DisabledCount = serverGroupInHostsFile\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Where(item =&gt; IsCommented(item.Line)).Count();\r\n}\r\n<\/pre>\n<p>With this Tally method defined, you must invoke it for each item in the server group collection. To do this, you actually need to go outside LINQ to the <b>ForEach<\/b> operator available on List and Array types. This operator lets you generate side effects, i.e. invoking other methods easily. One minor compatibility issue-since <b>ForEach<\/b> is only available for collections of type List&lt;T&gt; while the lingua franca of LINQ is IEnumerable&lt;T&gt;, you must use LINQ&#8217;s <b>ToList<\/b> operator to convert from one to the other. Now you have all the pieces to generate the fairly simple code to replace all the loops; this code is in HostSwitcher-B.linq:<\/p>\n<pre>projectDict.Keys\r\n\u00a0\u00a0\u00a0 .SelectMany(project =&gt; projectDict[project])\r\n\u00a0\u00a0\u00a0 .ToList()\r\n\u00a0\u00a0\u00a0 .ForEach(serverGroup =&gt; Tally(activeHostsFileData, serverGroup));\r\n<\/pre>\n<h3 id=\"fourteenth\">Conversion Stage C<\/h3>\n<p>For the next conversion, continue going upward in the original CreateMap method, now focusing on the inner of the two nested loops in step 2:<\/p>\n<pre class=\"lang:c# theme:vs2012\">bool groupAlreadyPresent = false;  foreach (var serverGroup in serverGroups)\r\n{\r\n\u00a0\u00a0\u00a0 if (serverGroup.Name.Equals(item.ServerGroupName))\r\n\u00a0\u00a0\u00a0 { groupAlreadyPresent = true; }\r\n}\r\nif (!groupAlreadyPresent)\r\n{ serverGroups.Add(\r\n\u00a0\u00a0\u00a0 new ServerGroup { Name = item.ServerGroupName, Project = item.Project }); }\r\n<\/pre>\n<p>The above code checks whether the current server group is already in the list of server groups and, if not, adds it. All of that preparatory code can be replaced by a simple LINQ expression, using the <b>Any<\/b> operator to do the very same check without having to specify how to do it. This code is in HostSwitcher-C.linq:<\/p>\n<pre class=\"lang:c# theme:vs2012\">if (!serverGroups  \u00a0\u00a0\u00a0 .Any(serverGroup =&gt; serverGroup.Name.Equals(item.ServerGroupName)))\r\n{ serverGroups.Add(\r\n\u00a0\u00a0\u00a0 new ServerGroup { Name = item.ServerGroupName, Project = item.Project }); }\r\n<\/pre>\n<h3 id=\"fifteenth\">Conversion Stage D<\/h3>\n<p>Continue toward the top of the original CreateMap method to step 1. You can eliminate a loop and a conditional with the most typical of LINQ forms, a <b>from &#8230; where &#8230; select<\/b> expression. Recall that the loop iterated through the collection, checked whether each line met a certain criteria, then decorated the line and added it to a new collection. With LINQ, again start with the collection. Then just restrict it to the lines of interest and project it into the new collection. The <b>let<\/b> operator is a handy LINQ mechanism for a temporary variable in the middle of the LINQ chain.<\/p>\n<pre class=\"lang:c# theme:vs2012\">var activeHostsFileData =  \u00a0\u00a0\u00a0 from line in hostFileData\r\n\u00a0\u00a0\u00a0 let m = FilteringRegex.Match(line)\r\n\u00a0\u00a0\u00a0 where m.Success\r\n\u00a0\u00a0\u00a0 select new\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 line,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 project = m.Groups[ProjectSubGroupIndex].ToString().Trim(),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serverGroup = m.Groups[ServerGroupSubGroupIndex].ToString().Trim()\r\n\u00a0\u00a0\u00a0 };\r\n<\/pre>\n<p>You will find the code for this in HostSwitcher-D.linq. This code also includes a retrograde step: The double loop in step 3, last seen in HostSwitcher-A.linq, is back. I did this primarily because it is a better lead-in to the next stage. But notice the trade-off indicated back in Table 2. By removing LINQ you can eliminate the HostDetail support class (really just a multiple-field container) and the Tally support method. So neither implementation is decidedly a better piece of code.<\/p>\n<h3 id=\"sixteenth\">Conversion Stage E<\/h3>\n<p>For this penultimate stage, the goal is to reduce the complexity of having one portion of code to build the dictionary (step 2) and a second portion to populate the enabled\/disabled counts within each dictionary entry (step 3). The code below (from HostSwitcher-E.linq) uses a single loop to go through the list of relevant host file lines. But this list (in activeHostsFileData) is different this time. Suppose that instead of each entry in the source list reflecting a single line in the hosts file, it now reflects all the information for a server group, however many lines that entails. Given that, you can then directly create a server group with its EnabledCount and DisabledCount and add that to the dictionary entry for the appropriate project; no need to go back through the data to find the counts and associate them with the right groups.<\/p>\n<pre class=\"lang:c# theme:vs2012\">foreach (var item in activeHostsFileData)  {\r\n\u00a0\u00a0\u00a0 if (!projectDict.ContainsKey(item.project))\r\n\u00a0\u00a0\u00a0 { projectDict[item.project] = new List&lt;ServerGroup&gt;(); }\r\n\u00a0\u00a0\u00a0 var serverGroups = projectDict[item.project];\r\n\u00a0\u00a0\u00a0 var serverGroup = new ServerGroup\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Name = item.serverGroup,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 EnabledCount = item.Lines.Where(line =&gt; !IsCommented(line)).Count(),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 DisabledCount = item.Lines.Where(line =&gt; IsCommented(line)).Count()\r\n\u00a0\u00a0\u00a0 };\r\n\u00a0\u00a0\u00a0 serverGroups.Add(serverGroup);\r\n<\/pre>\n<p>The other portion of this stage, then, is to create the revised activeHostsFileData collection. Compare the code here to that in stage D. The project and server group definitions have been moved out of the <b>select<\/b> clause and into temporary variables earlier on. This lets you perform a grouping operation to get the aggregated data required. The final projection (the select expression) now contains all the lines in the group.<\/p>\n<pre class=\"lang:c# theme:vs2012\">var activeHostsFileData =  \u00a0\u00a0\u00a0 from line in hostFileData\r\n\u00a0\u00a0\u00a0 let m = FilteringRegex.Match(line)\r\n\u00a0\u00a0\u00a0 let project = m.Groups[ProjectSubGroupIndex].ToString().Trim()\r\n\u00a0\u00a0\u00a0 let serverGroup = m.Groups[ServerGroupSubGroupIndex].ToString().Trim()\r\n\u00a0\u00a0\u00a0 where m.Success\r\n\u00a0\u00a0\u00a0 group line by new {project, serverGroup}\r\n\u00a0\u00a0\u00a0 into g\r\n\u00a0\u00a0\u00a0 select new {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 g.Key.project,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 g.Key.serverGroup,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Lines = from line in g select line\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 };\r\n<\/pre>\n<h3 id=\"seventeenth\">Final Conversion<\/h3>\n<p>If you look at the final code (HostSwitcher-final.linq) it is much more challenging to map it back to determine what changed from the previous stage. Rather than say you need to take a leap of faith :-), what I did at this point was start over with a much clearer picture in my head of what steps were involved to transform the lines in the hosts file into decorated dictionary entries. I outline my thought process below.<\/p>\n<p>Start aggressively by stating that you want to do something to produce a dictionary from scratch:<\/p>\n<pre>projectDict = <\/pre>\n<p>You should know what comes next-start with the collection:<\/p>\n<pre>hostFileData<\/pre>\n<p>You need to add some information to each line-the regular expression match containing information about the project and server group:<\/p>\n<pre class=\"lang:c# theme:vs2012\">.Select(line =&gt; new { line, m = FilteringRegex.Match(line) })<\/pre>\n<p>With the regular expression in hand it is trivial to restrict the collection to the relevant lines:<\/p>\n<pre>.Where(item =&gt; item.m.Success)<\/pre>\n<p>Now add on the other bits of information needed, the project and server group, and discard the regular expression match, which is no longer needed, by projecting the elements in the collection to a new form once again:<\/p>\n<pre class=\"lang:c# theme:vs2012\">.Select(item =&gt; new  {\r\n\u00a0\u00a0\u00a0 item.line,\r\n\u00a0\u00a0\u00a0 project = item.m.Groups[ProjectSubGroupIndex].ToString().Trim(),\r\n\u00a0\u00a0\u00a0 serverGroup = item.m.Groups[ServerGroupSubGroupIndex].ToString().Trim()\r\n})\r\n<\/pre>\n<p>At this point, you have a collection where each element is relevant and each element has everything needed to create the dictionary. In fact, you have already seen this collection-refer back to Figure 1. The goal is to create the finished dictionary in Figure 3.<\/p>\n<p>The easiest way to create a dictionary is to use LINQ&#8217;s native support for it, in the guise of the <b>ToDictionary<\/b> operator. To do this you need to specify a key and a value for each entry in the dictionary. The key is just the project name, as you have seen. The value is a list of server groups. Here you need to introduce some groups. First, group the input lines by common project and server group:<\/p>\n<pre class=\"lang:c# theme:vs2012\">.GroupBy(item =&gt; new { item.project, item.serverGroup }, item =&gt; item.line)\r\n<\/pre>\n<p>This results in groups where the key is the unique project and server group combination and the group contents is the list of lines that have that combination. Figure 4, left side, shows the first three of five such groups. This grouping does not quite yield what you need yet, so group again:<\/p>\n<pre>.GroupBy(projAndServer =&gt; projAndServer.Key.project)\r\n<\/pre>\n<p>That statement groups by projects alone because that is what you need for the dictionary keys. Note the special <b>Key<\/b> property available for a group that lets you access the project values. There are only two distinct projects in the sample data, thus this results in just two groups. Figure 4, right side, shows the first of these. Observe how the two levels of grouping are arranged.<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael6.jpg\" alt=\"1210-Michael6.jpg\" \/><\/p>\n<p class=\"caption\">Figure 4 Intermediate data in the LINQ chain: at left, after the first GroupBy and at right, after the second GroupBy<\/p>\n<p>With these groupings in place, you now have the material needed to pass to the <b>ToDictionary<\/b> method:<\/p>\n<pre class=\"lang:c# theme:vs2012\">.ToDictionary(\r\n\u00a0\u00a0\u00a0 project =&gt; project.Key,\r\n\u00a0\u00a0\u00a0 project =&gt; project.Select(item =&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new ServerGroup\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Name = item.Key.serverGroup,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 EnabledCount\u00a0 = item.Where(line =&gt; !IsCommented(line)).Count(),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 DisabledCount = item.Where(line =&gt;\u00a0 IsCommented(line)).Count()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 )\r\n);\r\n<\/pre>\n<p><b>ToDictionary<\/b> takes two parameters, a lambda expression for the key and for the value. The key is just the project, which is available in the <b>Key<\/b> property of the latest group. To generate the value, you reference the group data-remember that this is a collection. So the <b>Select<\/b> operator is going to generate a list of elements, one for each member of the collection. Each element is a ServerGroup because of the <b>new ServerGroup<\/b> statement. A ServerGroup, as you have seen, has three properties to specify. The Name comes from the inner group&#8217;s <b>Key<\/b> property. Finally, the EnabledCount and DisabledCount come from processing the inner group&#8217;s collection.<\/p>\n<p>Load this finished code (HostSwitcher-final.linq) in LINQPad to see how it works. Between each pair of LINQ operators is a Dump() call that is commented out. If you uncomment any or all of those you can see the intermediate data from start to finish. And, for completeness, here is the CreateMap method composed of the one line of LINQ code that you just dissected:<\/p>\n<pre class=\"lang:c# theme:vs2012\">private void CreateMap()  {\r\n\u00a0\u00a0\u00a0 projectDict = \r\n\u00a0\u00a0\u00a0 hostFileData\r\n\u00a0\u00a0\u00a0 .Select(line =&gt; new { line, m = FilteringRegex.Match(line) })\r\n\u00a0\u00a0\u00a0 .Where(item =&gt; item.m.Success)\r\n\u00a0\u00a0\u00a0 .Select(item =&gt; new\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 item.line,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 project = item.m.Groups[ProjectSubGroupIndex].ToString().Trim(),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serverGroup = item.m.Groups[ServerGroupSubGroupIndex].ToString().Trim()\r\n\u00a0\u00a0\u00a0 })\r\n\u00a0\u00a0\u00a0 .GroupBy(item =&gt; new { item.project, item.serverGroup }, item =&gt; item.line)\r\n\u00a0\u00a0\u00a0 .GroupBy(projAndServer =&gt; projAndServer.Key.project)\r\n\u00a0\u00a0\u00a0 .ToDictionary(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 project =&gt; project.Key,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 project =&gt; project.Select(item =&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new ServerGroup\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Name = item.Key.serverGroup,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 EnabledCount\u00a0 = item.Where(line =&gt; !IsCommented(line)).Count(),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 DisabledCount = item.Where(line =&gt;\u00a0 IsCommented(line)).Count()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 )\r\n\u00a0\u00a0\u00a0 );\r\n}\r\n<\/pre>\n<h2 id=\"eighteenth\">Tools to Help Learn LINQ<\/h2>\n<p>By this point you should have some feel for turning code into LINQ. You have seen that there are many different scenarios to consider and thus LINQ operators to apply; getting a good grasp of them can still take some effort. Here are a couple tips to give you a boost in that endeavor.<\/p>\n<h3 id=\"nineteenth\">Resharper Converts Your Code to LINQ<\/h3>\n<p>Well known and respected for its refactoring capability, code quality analysis, navigational aids, and more, the Visual Studio power tool Resharper also has a special ability with respect to LINQ: it can automatically convert a loop into a LINQ expression! Just like other refactorings and suggested code improvements, conversion to LINQ appears on Resharper&#8217;s list of actions in the appropriate context. To find such candidate code, first direct Resharper to analyze your solution or project (Resharper &gt;&gt; Inspect &gt;&gt; Code Issues in Current Project). This will populate a Visual Studio window entitled Inspection Results. Press the <b>Filter<\/b> button (Figure 5, top) to open the Filter Issues dialog. In the dialog, press the <b>Uncheck All<\/b> button to deselect all choices then select the two LINQ-specific choices under <b>Language Usage Opportunities<\/b> (Figure 5, bottom). Close out the dialog and now the Inspection Results window lists all and only the LINQ-convertible loops. As with any find or inspection window in Visual Studio, just double click on any leaf node in the issues tree to open that line in the editor.<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1210-Michael7.jpg\" alt=\"1210-Michael7.jpg\" \/><\/p>\n<p class=\"caption\">Figure 5 Using Resharper to Find Candidate Code for LINQ Conversion<\/p>\n<p>Resharper does one more trick: it can convert an expression using LINQ query syntax to lambda syntax! Unfortunately, these code candidates do not appear in the inspection window. So though you cannot jump to these pieces of code, it is fairly easy to recognize a LINQ query expression, since it looks quite different than other bits of code. Once you land on it, the choice to convert to lambda syntax will appear on the context menu.<\/p>\n<p>There is a tiny Visual Studio solution included in the code archive accompanying this article that gives you an example where you can try using Resharper to convert a plain loop to LINQ, and another where you can convert a LINQ expression written with query syntax into method syntax.<\/p>\n<h3 id=\"twentieth\">LINQPad Shows the SQL generated by your LINQ<\/h3>\n<p>Hearkening back to LINQPad, it has a neat ability when you are working with LINQ to SQL. Once you write a LINQ query and execute it, the output window in LINQPad offers a few buttons to show some alternate output. One is just labeled SQL. Pressing that reveals the SQL code that is generated from your LINQ query. This lets you see how LINQ queries map back to pure SQL queries. (Too bad it cannot go the other direction!)<\/p>\n<h2 id=\"tewntyfirst\">Conclusion<\/h2>\n<p>One of the best ways to learn about a technology is by example-by reading other people&#8217;s code, in this case. The chances are that you could typically do this quite effectively on your own, but my goal with this article was to make the experience even more productive for you: to provide not just code to read but a guide on what to take away from it. LINQ is a powerful technology that, as I stated earlier, lends itself well towards incremental use. I have presented a cross-section of LINQ operators to aid your creative juices; as with most technologies, though, it just scratches the surface. But with this introduction you should have a good foundation for further LINQ exploration.<\/p>\n<h2 id=\"twentysecond\">Footnotes<\/h2>\n<p id=\"footnote1\">[1] Comparing learning LINQ to learning C# is unfair: LINQ is just one element of a language that you presumably already know, while learning the C# language encompasses a more fundamental basket of concepts. A more apt comparison might be LINQ vs. WPF. Both are &#8220;add ons&#8221; to C# but before you can write a line of code in WPF you need to learn a great deal, indeed!<\/p>\n<p id=\"footnote3\">[2] Hence my whimsical title of LINQ Lycanthropy for this article: you get to watch live, before your very eyes, as the code changes from plain ol&#8217; C# code to LINQ!<\/p>\n<p>[3] A <i>lambda expression<\/i> is simply an anonymous function. Thus, the lambda expression.<\/p>\n<pre>n =&gt; n.Length<\/pre>\n<p>is equivalent to this conventional method:<\/p>\n<pre class=\"lang:c# theme:vs2012\">int GetLength(string n) { return n.Length; }<\/pre>\n<p>Lambda expressions provide a handy shortcut syntax for simple methods: not only is the method itself reduced but you eliminate a separate method call and method definition.<\/p>\n<p id=\"footnote4\">[4]<a href=\"http:\/\/www.linqpad.net\/\">LINQPad<\/a> is a free utility created by Joe Albahari. It supports C#, VB, F#, and SQL, and lets you test and experiment with code rapidly, without the overhead of Visual Studio projects. You can execute not just programs but one or more individual statements or even just an expression. My recent article <a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/linq-secrets-revealed-chaining-and-debugging\/\">LINQ Secrets Revealed: Chaining and Debugging<\/a> provides a great introduction to using LINQPad and even bringing its great data visualization capabilities back into Visual Studio.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>LINQ is one of the few technologies that you can start to use without a lot of preliminary learning. Also, it lends itself to learning by  trying out examples. With Michael&#8217;s help, you can watch as your conventional C# code changes to ravenous LINQ before your very eyes.<\/p>\n<p>&hellip;<\/p>\n","protected":false},"author":221868,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4229,4371,4706,5190],"coauthors":[6802],"class_list":["post-1060","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-framework","tag-c","tag-linq","tag-michael-sorens"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1060","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221868"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1060"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1060\/revisions"}],"predecessor-version":[{"id":72947,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1060\/revisions\/72947"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1060"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1060"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1060"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1060"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}