Conditional LINQ Clauses

Programming LINQ C#

There are times we want to apply an expression only when the system provides a reason to do so. A typical example is filtering our dataset based on the current user’s role within our system. We may also want to apply a different transformation based on a system configuration setting.

For these use cases, we can write an extension method that applies to IQueryable and IEnumerable interfaces. Targeting these two interfaces gives us the most coverage across most LINQ provider implementations.

using System.Collections.Generic;
using System.Linq;

public static class EnumerableHelpers
{
public static IQueryable<T> If<T>(
this IQueryable<T> query,
bool should,
params Func<IQueryable<T>, IQueryable<T>>[] transforms)
{
return should
? transforms.Aggregate(query,
(current, transform) => transform.Invoke(current))
: query;
}

public static IEnumerable<T> If<T>(
this IEnumerable<T> query,
bool should,
params Func<IEnumerable<T>, IEnumerable<T>>[] transforms)
{
return should
? transforms.Aggregate(query,
(current, transform) => transform.Invoke(current))
: query;
}
}

The extension methods will only apply the query transformations when the should value is true. The boolean can originate from any source within our application.

Here is an example that filters an array of values based on whether a user is a “regular” user or a “super” user.

class Program
{
static void Main(string[] args)
{
var data = new[]
{
new {user = "captain", data = "launch codes"},
new {user = "doctor", data = "medicine"},
new {user = "lawyer", data = "law"}
};

var administratorFlags = new[] { true, false };
var user = "captain";

foreach (var regularUser in administratorFlags)
{
var results =
data
.If(regularUser,
q => q.Where(x => x.user == user)
)
.Select(x => x.data)
.ToList();

Console.WriteLine(new string('.', 50));
Console.WriteLine($"I am a {(regularUser ? "regular" : "SUPER")} {user}");
Console.WriteLine($"My data includes {string.Join(", ", results)}.");
}
Console.WriteLine(new string('.', 50));
}
}

Running the program gets us the filtered and unfiltered results, respectively:

I am a regular captain
My data includes launch codes.

I am a SUPER captain
My data includes launch codes, medicine, law.