C#6: Support for .NET Framework 2.0 to 4.5

A colleague of mine, Eric Charnesky, asked me if C#6 language features would work in .NET Framework versions other than 4.6. I was pretty confident that the features were almost all1 just syntactical seasoning, I thought I would find out.

The TL;DR is yes, C#6 features will work when compiled against .NET 2.0 and above, with a few caveats.

  1. Async/await requires additional classes to be defined since the Task Parallel Library, `IAwaitable` and other types were not part of .NET 2.0.
  2. The magic parts of string interpolation need some types to be defined (thanks to Thomas Levesque for catching this oversight).
  3. Extension methods need the declaration of `System.Runtime.CompilerServices.ExtensionAttribute` so that the compiler can mark static methods as extension methods.

Rather than just try .NET 4.5, I decided to go all the way back to .NET 2.0 and see if I could write and execute a console application that used all the following C#6 features:

The code I used is not really important, though I have included it at the end of this post if you want to see what I did. The only mild stumbling block was the lack of obvious extension method support in .NET 2.0. However, extension methods are a language-only feature; all that is needed to make it work is an attribute that the compiler can use to mark methods as extension methods. Since .NET 2.0 doesn't have this attribute, I added it myself.

Exclusions

You might have noticed that I did not verify a couple of things. First, I left out the use of `await` in `try`/`catch` blocks. This is because .NET 2.0 does not include the BCL classes that the compiler expects when generating the state machines that drive async code. You might be able to find a third-party implementation that would add support, but my brief3 search was fruitless. That said, this feature will definitely work in .NET 4.5 as it is an update to how the compiler builds the code.

Second, I did not intentionally test the improved overload resolution. The improvements mostly seem to relate to resolution involving overloads that take method groups and nullable types. Unfortunately, in .NET 2.0 there was were no `Func` delegate types nor nullable value types (UPDATE: Nullable types totally existed in .NET 2.0 and C#2; thanks to Thomas Levesque for pointing out my strange oversight here – I blame the water), making it difficult to craft an example that would demonstrate this improvement. However, overload resolution affects how the compiler selects which method to use for a particular call site. Once the compiler has made the selection, it is fixed within the compiled output and as such, the version of the .NET framework has no bearing on whether the resolution is correct4.

Did it work?

With the test code written, I compiled and ran it. A console window flickered and Visual Studio returned. The code had run but I had forgotten to put anything in there that would give me chance to read the output. So, I dropped a breakpoint in at the end, and then ran it under the debugger. As I had suspected it might, everything worked.

Testing under .NET 2.0 runtime on Windows XP
Testing under .NET 2.0 runtime on Windows XP

Then I realised I was still executing it on a machine that had .NET 4.6 and therefore the .NET 4 runtime; would it still work under the .NET 2 runtime? So, I cracked open5 a Windows XP virtual machine from modern.ie and ran it again. It didn't work, because Windows XP did not come with .NET 2.0 installed (it wasn't even included in any of the service packs), so I installed it and tried once more. As I had suspected it might, everything worked.

In conclusion

If you find yourself still working with old versions of the .NET framework or the .NET runtime, you can still use and benefit from most features of C#6. I hope my small effort here is helpful. If you have anything to add, please comment.

Here Lies The Example Code6

using System;
using System.Collections.Generic;
using static System.Math;

namespace System.Runtime.CompilerServices
{
    [AttributeUsage( AttributeTargets.Method )]
    public class ExtensionAttribute : Attribute
    {
    }
}

namespace CSharp6andNET2
{
    internal class Program
    {
        public delegate bool Filter( ArgumentException ex, string argName );

        public bool DoFilter( Filter test, ArgumentException ex, string argName )
        {
            return test( ex, argName );
        }

        private static void Main( string[] args )
        {
            Filter x = ( ArgumentException ex, string argName ) => ex.ParamName == argName;
            for ( int count = 0; count < 2; count++ )
            {
                try
                {
                    ExceptionFilterTest( count == 0 );
                }
                catch ( ArgumentException e ) when (x( e, "argumentName" ))
                {
                    Console.WriteLine( "Logged filtered exception" );

                    var test = new TestClass();
                    Console.WriteLine(
                        $"{nameof( test.Count )}: {test.Count}, {nameof( test.Count2 )}: {test.Count2}{nameof( test.Count3 )}: {test.Count3}, {nameof( test.Count4 )}: {test.Count4( 1 )}" );

                    var list = new List<int>
                    {
                        "9",
                        "25",
                        "36",
                        16,
                        4,
                        64
                    };

                    Console.WriteLine( "List" );
                    foreach ( var n in list )
                    {
                        Console.WriteLine( Sqrt( n ) );
                    }

                    var dictionary = new Dictionary<int, string>
                    {
                        [ 4 ] = "Test",
                        [ 2 ] = null,
                        [ 45 ] = null,
                        [ 34 ] = null,
                        [ 200 ] = null,
                        [ 16 ] = "Another test"
                    };

                    foreach ( var k in dictionary )
                    {
                        Console.WriteLine( $"{k.Key}: {k.Value?.Substring( 0, 3 )}" );
                    }
                }
                catch ( Exception )
                {
                    Console.WriteLine( "Logged exception" );
                }
            }
        }

        private static void ExceptionFilterTest( bool filterable )
        {
            if ( filterable ) throw new ArgumentException( "Exception", "argumentName" );

            throw new Exception( "Exception" );
        }
    }

    internal static class Extensions
    {
        public static void Add( this List<int> list, string value )
        {
            list.Add( Int32.Parse( value ) );
        }
    }

    internal class TestClass
    {
        public int Count { get; } = 6;
        public int Count2 { get; set; } = 6;
        public int Count3 => 6;
        public int Count4( int x ) => x + 6;
    }
}

 

  1. Async/await requires the TPL classes in the BCL, extension methods need the ExtensionAttribute, and exception filters require some runtime support []
  2. The Elvis's []
  3. very brief []
  4. I realise many of the C#6 features could be left untested for similar reasons since almost all are compiler changes that do not need framework support, but testing it rather than assuming it is kind of the point []
  5. Waited an hour for the IE XP virtual machine to download and then get it running []
  6. Demonstrable purposes only; if you take this into production, on your head be it []

C#6: String Interpolation

Continuing the trend of my recent posts looking at the new features of C#6, this week I want to look at string interpolation.

Prior to C#6, string interpolation (or string formatting) was primarily the domain of the .NET framework and calls like `string.Format()` and `StringBuilder.AppendFormat()`1 as in the following example:

var aString = "AString";
var formatString = string.Format("The string, '{0}', has {1} characters.", aString, aString.Length);

With string interpolation in C#6, this can be written as:

var aString = "AString";
var formatString = $"The string, {aString}, has a {aString.Length} characters.";

This is a little easier to read while also reducing what has to be typed to achieve the desired result. The contents of the braces are evaluated as strings and inserted into the resultant string. Under the hood, this example compiles down to the same `string.Format` call that was made in the earlier example. The same composite formatting power is there to specify things like significant figures and leading zeroes. If you need a culture-invariant string, there is a handy static method in the new `System.FormattableString` class called `Invariant()`. If you wrap your string with this `Invariant()` method, you will get the string formatted against the invariant culture.

Magic

Of course, to end the story there without discussing the compiler magic would do a disservice to this new feature. In the example above, the result of the interpolation was stored in a variable with type `var`. This means the type is inferred by the compiler, which infers `string` and then performs appropriate compiler operations to turn our interpolated string into a call to `string.Format()`. This means that we don't have to do anything else to use this feature and get formatted strings. However, we can make the compiler do something different by rewriting the line like this2:

FormattableString formatString = $"The string, {aString}, has a {aString.Length} characters.";

We have now specified that we are using a variable of type `FormattableString`. With this declaration, the compiler changes its behavior and we get a `FormattedString` object that represents the interpolated string. From this object, we can get the `Format` string that could be passed to a call that takes a format string, such as `string.Format()` (there are several others in types like `Console`, `StringBuilder`, and `TextWriter`). We can also retrieve the number of arguments3 in the string using `ArgumentCount`, and use `GetArgument()` and `GetArguments()` to retrieve the values of those arguments. Using a combination of `Format` and `GetArguments()`, we can pass this information to a different call that might reuse or extend it to produce a different message. Finally, we can use the `ToString()` call to specify an `IFormatProvider`, allowing us to format the string according to a specific culture.

By telling the compiler that we want a `FormattableString` we get all this extra information to use as we see fit. If you look at the arguments using either of the `Get..` methods, you will see that the values have already been evaluated, so you can be assured that they won't change as you process the string. I'm sure there are situations where you might find this additional access to the formatting invaluable, such as when creating compound error messages, or perhaps doing some automatic language translation.

In conclusion…

There's not much else for me to say about C#6's string interpolation except to highlight one gotcha that I have hit a couple of times. The next two examples should illustrate appropriately:

Console.WriteLine($"{DateTime.Now}: I'm writing DateTime.Now to the console");
Console.WriteLine("{DateTime.Now}: I'm writing DateTime.Now to the console");

Here is what these two examples will output:

9/8/2015 11:11:43 AM: I'm writing DateTime.Now to the console.
{DateTime.Now}: I'm writing DateTime.Now to the console.

It's hard to argue with either of them, after all, they both wrote an interpretation of `DateTime.Now` to the console, but the first one is perhaps a more useful output4.

So why did the second example not work? You may have already spotted the answer to that question, especially if you're a VB programmer; it's the `$` at the start of the first example's string.  This `$` tells the compiler that we are providing a string for interpolation. It's an easy thing to miss and if you forget it (or perhaps, in rare cases, add it erroneously) you'll likely only spot the mistake through thorough testing5 or customer diligence6. As always, learn the failure points and work to mitigate them with code reviews and tests. I suspect the easiest mitigation may be to always use the interpolation style strings unless a situation demands otherwise.

And that's it for this week. What do you think of the new string interpolation support? Will you start using it? If not, why not? Do you have any cool ideas for leveraging the additional information provided by `FormattableString`? Please share in the comments.

If you're interested in my other posts on some of the new things introduced by C#6, here are links to posts I have written thus far:

  1. The `+` operator can be used in conjunction with `ToString()` but it can get messy to read and is very hard to localize []
  2. We could also cast the interpolated string to `FormattableString` and leave the variable as `var`. []
  3. Each inserted value is an argument []
  4. Except when providing examples in a blog []
  5. Unit tests or otherwise []
  6. Write automated tests and test manually; let's not use customers as QA []

C#6: Using Static Types and Extension Methods

This week I thought I would continue from the last couple of posts on the new language features introduced in C#6 and look at the changes to the `using` keyword.

Up until the latest syntax, `using` was overloaded in three different ways1.

  1. To import types from a specific namespace, reducing the need to fully quality those types when referencing them in subsequent code.
    using System.Collections;
  2. To alias namespaces and types in order to resolve ambiguities when types share a name but different namespaces.
    using Drawing = System.Windows.Drawing; // Namespace alias
    using RectangleShape = System.Windows.Shapes.Rectangle; // Type alias
    
  3. To define a scope at the end of which an object will be disposed
    using (var stream = new MemoryStream())
    {
        // Stuff using the stream
    }

With C#6 comes an additional overload that allows us to import methods from within a specific static class. By specifying the `static` keyword after `using`, we can give the name of a static class containing the members we want to import. Doing this allows us to reference the methods as though they were members of our class.

Using Static

Consider `System.Math`; prior to this updated syntax, using the various methods on the `System.Math` class would require either specifying the fully qualifed type name, `System.Math` or, if `using System` were specified, just the type name, `Math`. Now, by specifying `using static System.Math` we can reference the methods of the `Math` class as though they were members of the class invoking them (without a `System.Math` or `Math` prefix). In this example, `Math.Abs()` is called as just `Abs()`.

using static System.Math;

public class MyClass
{
    public void DoStuff(int value)
    {
        var absoluteValue = Abs(value);
        Console.WriteLine(absoluteValue);
    }
}

As with other additions in C#6, this seems to be aimed at improving developer productivity as it leads to less overall typing when using the methods of a static class. However, the new `using static` syntax also allows for very targeted inclusion of static classes without the rest of their containing namespace, previously only possible with an alias, such as `using Math = System.Math`. This targeting ability, while not really adding anything for regular static methods, makes a significant difference for extension methods.

Extension Methods

As you probably know, extension methods are just fancy static methods, they can even be invoked as would a regular static method. However, extension methods can also be invoekd as though they where member methods of a variable or literal value. For example, both the following examples compile to the same code (assuming we have an enumerable called `list`).

list.Where(x <= 5);
Enumerable.Where(list, x <= 5);

However, before the `using static` syntax, including extension methods was a bit uncontrolled. If you wanted the extension methods in `System.Linq.Enumerable`, you had to include the entire `System.Linq` namespace; there was no way to include only the `Enumerable` static class. In some circumstances, this inability to include just the static class led to annoying type name clashes and occasionally unexpected overload resolution ambiguities or surprises. Now, with `using static` we can specify the exact class of extension methods we want to include and ignore the rest of the containing namespace.

With all that said, there is a notable difference between including regular methods of a static class and extension methods of a static class when importing via `using static <namespace>.<static class>`2.

Subtle Difference

When a static class is imported with `using static`, the way a method can be invoked depends on whether it is an extension method or not. For example, imagine we have a static class called `MyStaticClass` and it has a regular3 static method on it called `Print` that takes a `string`. When included via `using static`, `Print` could be used like this:

void Main()
{
    MyStaticClass.Print("this string");
    // or...
    Print("this string");
}

However, if instead `Print` were an extension method on type `string`, including `MyStaticClass` via `using static` would limit `Print` to being used like this:

void Main()
{
    MyStaticClass.Print("this string");
    // or...
    "this string".Print();
}

Note how in both examples , `Print` can be invoked as a traditional static method when the containing type is referenced, as in `MyStaticClass.Print()`, but their invocation varies when `using static` imports the class. In that second scenario, non-extension static methods are invoked as though they are methods on the current type, where as extension methods are invoked only as though they are methods on a variable. For the extension method version of `Print`, the following is not allowed:

Print("this string");

To use this argument-style syntax with an extension method, we must resort to the same syntax we would have used before `using static`, specifying the type name before the method:

MyStaticClass.Print("this string");

Though I feel it is clear and intuitive, this is a subtle difference worth understanding, as it can lead to breaking changes. Consider if you were refactoring the methods of a static class from extension method to regular static method or vice versa, and that class were imported somewhere with `using static`; any invocations that were not prefixed with the static class name would fail to compile.

In Conclusion

Overall, I like the new `using static` syntax; I believe the differences in method invocation from how static class methods are normally invoked makes sense and I hope you do too. Like all the other features of C#, there will be times to use this feature and times to let it go in favour of something clearer and more appropriate. For me, the ability to pluck a specific class and its extension methods from a namespace without importing the rest of that namespace is the most useful aspect of `using static` and probably what I will use most. How about you? Do you see yourself adding `using static` to your coding arsenal, or is it going to languish in your scrapbook of coding evil? Do tell.

  1. The MSDN docs say two different ways, but it was clearly three and is now three and a halfish []
  2. However, unlike the subtle difference I highlighted in my last post, thankfully, the compiler will catch this one []
  3. as in not an extension method []

Getting Information About Your Git Repository With C#

During a hackathon not so long ago, I wanted to incorporate some source control data into my .NET assembly version information for the purposes of troubleshooting installations, making it easier for people to report the code in which they found a bug, and making it easier for people to find the code in which a bug was found1. The plan was to automatically encode the branch, the commit hash, and whether there were local commits or local changes into the `AssemblyConfiguration` attribute of my assemblies during the build.

At the time, I hacked together the `RepositoryInformation` class below that wraps the command line tool to extract the required information. This class supported detecting if the directory is a repository, checking for local commits and changes, getting the branch name and the name of the upstream branch, and enumerating the log. Though it felt a little wrong just wrapping the command line (and seemed pretty fragile too), it worked. Unfortunately, it was dependent on git being installed on the build system; I would prefer the build to get everything it needs using package management like NuGet and npm2.

class RepositoryInformation : IDisposable
{
    public static RepositoryInformation GetRepositoryInformationForPath(string path, string gitPath = null)
    {
        var repositoryInformation = new RepositoryInformation(path, gitPath);
        if (repositoryInformation.IsGitRepository)
        {
            return repositoryInformation;
        }
        return null;
    }
    
    public string CommitHash
    {
        get
        {
            return RunCommand("rev-parse HEAD");
        }
    }
    
    public string BranchName
    {
        get
        {
            return RunCommand("rev-parse --abbrev-ref HEAD");
        }
    }
    
    public string TrackedBranchName
    {
        get
        {
            return RunCommand("rev-parse --abbrev-ref --symbolic-full-name @{u}");
        }
    }
    
    public bool HasUnpushedCommits
    {
        get
        {
            return !String.IsNullOrWhiteSpace(RunCommand("log @{u}..HEAD"));
        }
    }
    
    public bool HasUncommittedChanges
    {
        get
        {
            return !String.IsNullOrWhiteSpace(RunCommand("status --porcelain"));
        }
    }
    
    public IEnumerable<string> Log
    {
        get
        {
            int skip = 0;
            while (true)
            {
                string entry = RunCommand(String.Format("log --skip={0} -n1", skip++));
                if (String.IsNullOrWhiteSpace(entry))
                {
                    yield break;
                }
                
                yield return entry;
            }
        }
    }
    
    public void Dispose()
    {
        if (!_disposed)
        {
            _disposed = true;
            _gitProcess.Dispose();
        }
    }
    
    private RepositoryInformation(string path, string gitPath)
    {
        var processInfo = new ProcessStartInfo
        {
            UseShellExecute = false,
            RedirectStandardOutput = true,
            FileName = Directory.Exists(gitPath) ? gitPath : "git.exe",
            CreateNoWindow = true,
            WorkingDirectory = (path != null && Directory.Exists(path)) ? path : Environment.CurrentDirectory
        };
        
        _gitProcess = new Process();
        _gitProcess.StartInfo = processInfo;
    }
    
    private bool IsGitRepository
    {
        get
        {
            return !String.IsNullOrWhiteSpace(RunCommand("log -1"));
        }
    }
    
    private string RunCommand(string args)
    {
        _gitProcess.StartInfo.Arguments = args;
        _gitProcess.Start();
        string output = _gitProcess.StandardOutput.ReadToEnd().Trim();
        _gitProcess.WaitForExit();
        return output;
    }
    
    private bool _disposed;
    private readonly Process _gitProcess;
}

If I were to approach this again today, I would use the LibGit2Sharp NuGet package or something similar3. Below is an updated version of `RepositoryInformation` that uses LibGit2Sharp instead of git command line. Clearly, you could forego any type of wrapper for LibGit2Sharp and I probably would if I were incorporating this into a bigger task like the one I originally had planned.

class RepositoryInformation : IDisposable
{
    public static RepositoryInformation GetRepositoryInformationForPath(string path)
    {
        if (LibGit2Sharp.Repository.IsValid(path))
        {
            return new RepositoryInformation(path);
        }
        return null;
    }
    
    public string CommitHash
    {
        get
        {
            return _repo.Head.Tip.Sha;
        }
    }
    
    public string BranchName
    {
        get
        {
            return _repo.Head.Name;
        }
    }
    
    public string TrackedBranchName
    {
        get
        {
            return _repo.Head.IsTracking ? _repo.Head.TrackedBranch.Name : String.Empty;
        }
    }
    
    public bool HasUnpushedCommits
    {
        get
        {
            return _repo.Head.TrackingDetails.AheadBy > 0;
        }
    }
    
    public bool HasUncommittedChanges
    {
        get
        {
            return _repo.RetrieveStatus().Any(s => s.State != FileStatus.Ignored);
        }
    }
    
    public IEnumerable<Commit> Log
    {
        get
        {
            return _repo.Head.Commits;
        }
    }
    
    public void Dispose()
    {
        if (!_disposed)
        {
            _disposed = true;
            _repo.Dispose();
        }
    }
    
    private RepositoryInformation(string path)
    {
        _repo = new Repository(path);
    }

    private bool _disposed;
    private readonly Repository _repo;
}

I have yet to use any of this outside of my hackathon work or this blog entry, but now that I have resurrected it from my library of coding exploits past to write about, I might just resurrect the original plans I had too. Whether that happens or not, I hope you found this useful or at least a little interesting; if so, or if you have some suggestions related to this post, please let me know in the comments.

  1. Sometimes, like a squirrel, you want to know which branch you were on []
  2. I had looked at NuGet packages when I was working on the original hackathon project, but had decided not to use one for some reason or another (perhaps the available packages did not do everything I wanted at that time) []
  3. PowerShell could be a viable replacement for my initial approach, but it would suffer from the same issue of needing git on the build system; by using a NuGet package, the build includes everything it needs []

LINQ: Notation, Syntax, and Snags

Welcome to the final post in my four part series on LINQ. So far, we've talked about:

For our last look into LINQ (at least for this mini-series), I want to tackle the mini-war of "dot notation" versus "query syntax", and look at some of the pitfalls that can be avoided by using LINQ responsibly.

Let Battle Commence…

For anyone who has written LINQ using C# (or VB.NET), you are probably aware that there is more than one way to express the query (two of which, sane people might use):

  1. Old school static method calls
  2. Method syntax
  3. Query syntax

No one in their right mind should be using the first of these options; extension methods were invented to alleviate the pain that would be caused by writing LINQ this way1. Extension methods, static methods that can be called as though member methods, are the reason why we have the second option of method syntax (more commonly known as dot notation or fluent notation). The final option, query syntax, is also known as "syntactical sugar", some language keywords that can make coding easier. These keywords map to concepts found in LINQ methods and query syntax is what gives LINQ it's name; Language INtegrated Query2.

They all map to the same thing, a sequence of methods that can be executed, or translated into an expression tree, evaluated by a LINQ provider, and executed. Anything written in one of these approaches can be written using the others. There is often contention on whether to use dot notation or query syntax, as if one is inherently better than the other, but as we all know, only the Sith deal in absolutes3.  Hopefully, by the end of these examples you will see how each has its merits.

Why are LINQ queries not always called like regular methods?

Because sometimes, such as in LINQ-to-SQL or LINQ-to-Entity Framework, the method calls need to be translated into SQL or some other querying syntax, allowing queries to take advantage of server-side querying optimizations. For a more in-depth look at all things LINQ, including the way the language keywords map to the method calls, I recommend looking at Jon Skeet's Edulinq series, which is available as a handy e-book.

Before we begin, here is a quick summary of the C# keywords that we have for writing queries in query syntax: `from`, `group`, `orderby`, `let`, `join`, `where` and `select`.  There are also contextual keywords to be used in conjunction with one or two of the main keywords:`in`, `into`, `ascending`, `descending`, `by`, `on` and `equals`. Each of these keywords has a corresponding equivalent method or methods in LINQ although it can sometimes be a little more complicated as we shall see.

So, let us look at an example and see how it can be expressed using dot notation and query syntax4). For an example, let us look at a simple projection of people to their last names.

public struct Person
{
    public Person(string first, string last, DateTimeOffset dateOfBirth) : this()
    {
        FirstName = first;
        LastName = last;
        DateOfBirth = dateOfBirth;
    }
    
    public string FirstName { get; private set; }
    public string LastName { get; private set; }
    public DateTimeOffset DateOfBirth { get; private set; }
}

public static class Data
{
    public static IEnumerable<Person> People = new[] {
        new Person("John", "Smith", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 34 )),
        new Person("Bill", "Smith", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 20 )),
        new Person("Sarah", "Allans", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 19 )),
        new Person("John", "Johnson", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 44 )),
        new Person("James", "Jones", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 78 )),
        new Person("Alex", "Jones", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 30 )),
        new Person("Mabel", "Thomas", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 29 )),
        new Person("Sarah", "Brown", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 23 )),
        new Person("Gareth", "Smythe", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 100 )),
        new Person("Gregory", "Drake", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 90 )),
        new Person("Michael", "Johnson", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 56 )),
        new Person("Alex", "Smith", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 22 )),
        new Person("William", "Pickwick", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 17 )),
        new Person("Marcy", "Dickens", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 18 )),
        new Person("Erica", "Waters", DateTimeOffset.Now - TimeSpan.FromDays( 365 * 26 ))
    };
}
Data.People.Select(p => p.LastName);
from person in Data.People
select person.LastName;

These two queries do the exact same thing, but I find that the dot notation wins out because it takes less typing and it looks clearer. However, if we decide we want to only get the ones that were born before 1980, things look a little more even.

Data.People
    .Where(p => p.DateOfBirth.Year < 1980)
    .Select(p => p.LastName)
from person in Data.People
where person.DateOfBirth.Year < 1980
select person.LastName;

Here, there is not much difference between them, so I'd probably leave this to personal preference5. However, as soon as we want a distinct list, the dot notation starts to win out again because C# does not contain a `distinct` keyword (though VB.NET does).

Mixing dot notation and query syntax in a single query can look messy, as shown here:

(from person in Data.People
where person.DateOfBirth.Year < 1980
select person.LastName).Distinct()

So, I prefer to settle on just one style of LINQ declaration for any particular query, or to use intermediate variables and separate the query into parts (this is especially useful on complex queries as it also provides clarity; being terse is cool, but it is unnecessary, and a great way to get people to hate you and your code).

Data.People
    .Where(p => p.DateOfBirth.Year < 1980)
    .Select(p => p.LastName)
    .Distinct();
var lastNames = from person in Data.People
                where person.DateOfBirth.Year < 1980
                select person.LastName;
lastNames.Distinct();

The `Distinct()` method is not the only LINQ method that has no query syntax alternative, there are plenty of others like `Aggregate()`, `Except()`, or `Range()`. This often means dot notation wins out or is at least part of a query written in query syntax. So, thus far, dot notation seems to have the advantage in the battle against query syntax. It is starting to look like some of my colleagues are right, query syntax sucks. Even if we use ordering or grouping, dot notation seems to be our friend or at least is no more painful than query syntax:

Data.People
    .OrderBy (p => p.LastName)
    .ThenBy (p => p.FirstName)
    .GroupBy(p=>p.DateOfBirth.Year);
from person in Data.People
orderby person.LastName,
        person.FirstName
group person by person.DateOfBirth.Year;

However, it is not always so easy. What if we want to introduce variables, group something other than the original object, or use more than one source collection? It is in these scenarios where query syntax irons a lot more of the complexity. Let's assume we have another collection containing newsletters that we need to send out to all our people. To generate the individual mailings, we would need to combine these two collections6.

Data.People.SelectMany(
    person => newsletters,
    (person, newsletter) => new {person,newsletter} );
from person in Data.People
from newsletter in newsletters
select new {person, newsletter};

I know which one is clearer to read and easier to remember when I need to write a similar query. The dot notation example makes me think for a minute what it is doing; projecting each person to the newsletters collection and, using `SelectMany()`, flattening the list then selecting one result per person/newsletter combination. Our query syntax example is doing the same thing, but I don't need to think too hard to see that. Query syntax is starting to look useful.

If we were to throw in some mid-query variables (useful to avoid calculating something multiple times or to improve clarity), or join collections, query syntax becomes really useful. What if each newsletter is on a different topic and we only want to send newsletters to people who are interested in that topic?

people.SelectMany(
    person => person.Value,
    ( person, topic ) => new
    {
        person,
        topic
    } ).Join(
        newsletters,
        t => t.topic,
        newsletter => newsletter.Value,
        ( t, newsletter ) => new
        {
            t.person,
            newsletter
        } );
from person in Data.People
from topic in person.Topics
join newsletter in newsletters on topic equals newsletter.Topic
select new {person, newsletter};

I know for sure I would need to go look up how to do that in dot notation7. Query syntax is an easier way to write more complex queries like this and provided that you understand your query chain, you can declare clear, performant queries.

 

In conclusion…

In this post I have attempted to show how both dot notation and query syntax (aka fluent notation) have their vices and their virtues, and in turn, armed you with the knowledge to choose wisely.

So, think about whether someone can read and maintain what you have written. Break down complex queries into parts. Consider moving some things to lazily evaluated methods. Understand what you are writing; if you look at it and have to think about why it works, it probably needs reworking. Always favour clarity and simplicity over dogma and cleverness; to draw inspiration from Jurassic Park, even though you could, stop to think whether you should.

LINQ is a complex feature of C# and .NET (and all the other .NET languages) and there are many things I have not covered. So, if you have any questions, please leave a comment. If I can't answer it, I will hopefully be able to direct you to someone who can. Alternatively, check out Edulinq by the inimitable Jon Skeet, head over to StackOverflow where there is an Internet of people waiting to help (including Jon Skeet), or get binging (googling, yahooing, altavistaring, whatever…)8.

And that brings us to the end of this series on LINQ. From deferred execution and the query chain to dot notation versus query syntax, I hope that I have managed to paint a favourable picture of LINQ, and helped to clear up some of the prejudices and confusions that surround it. LINQ is a powerful weapon in the arsenal of a .NET programmer; to not use it, would be a waste.

  1. Just the thought of the nested method calls or high number of placeholder variables makes me shudder []
  2. I guess LIQ was too suggestive for Microsoft []
  3. That statement is an absolute, Obi Sith Kenobi []
  4. I am definitely leaving the nested static methods approach to you as an exercise (in futility []
  5. Though if you changed the `person` variable to `p`, there is less typing in the query syntax , if that is a metric you are concerned with []
  6. Yes, a nested `foreach` can achieve this simple example, but this is just illustrative, and I'd argue cleaner than a `foreach` approach []
  7. That's why I cheated and wrote it in query syntax, then used Resharper to change it to dot notation for me []
  8. Back in my day, it was called searching…grumble grumble []