Tuesday, 2 December 2014

Useful LINQ Extensions You Might Not Know

If you've used LINQ for any period of time then you've no doubt come to appreciate the power, abstraction of responsibilities and expressiveness of it. You'll be used to extension methods such as Select, Where, Group and so on, but there are a few gems in the System.LINQ library that you just don't know until you know.

SelectMany

No doubt you're familiar with the Select extension method. SelectMany is similar, but produces a flat result set instead of a relational one. So when you would ordinarily work with Select like so:

public class Parent
{
    public string Name { get; set; }
    public List<string> Children { get; set; }
}

// The below gives us a list of lists...
var children = parents.Select(s => s.Children);

// ...which means going through them like this:
foreach (var childGroup in children)
{
    foreach (var child in childGroup)
    {
        // Do work here
    }
}

You can, instead, use SelectMany to flatten the results!

var children = parents.SelectMany(s => s.Children);

foreach (var child in children)
{
    // Do work here
}

If you need access to the parent as well as the child for every row like a SQL join, you can add a result selector:

var relationships = 
    parents.SelectMany(
               s => s.Children, 
               (parent, child) => new { parent, child });

foreach (var relationship in relationships)
{
    // Do work here
    // i.e. relationship.parent.Name or relationship.child
}

Cast

If you've ever needed to cast the elements of an enumerable to a different Type, you've probably written it like this:

var specificEnumerable = originalEnumerable
                            .Select(s => (SpecificType)s);

You can write this more expressively using the Cast method:

var specificEnumerable = originalEnumerable
                            .Cast<SpecificType>();

OfType

Cast is all well and good so long as the items in the enumerable are all of the same Type, but there are times when you have a mixture of Types and only want the items of a particular Type. You may be tempted to write the following:

var onlySpecificEnumerable = originalEnumerable
                                .Where(w => w is SpecificType)
                                .Select(s => (SpecificType)s);
// or, perhaps:
var onlySpecificEnumerable = originalEnumerable
                                .Select(s => s as SpecificType)
                                .Where(w => w != null);

The OfType extension performs the same filter plus cast action as the above, but with cleaner syntax and less room for mistakes!

var onlySpecificEnumerable = originalEnumerable
                                .OfType<SpecificType>();

No comments:

Post a Comment