I have a small utility extension method that performs some null checks on some LINQ extension methods in IEnumerable<T>. The code looks like this
public static class MyIEnumerableExtensions
{
// Generic wrapper to allow graceful handling of null values
public static IEnumerable<T> NullableExtension<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
{
if (first == null && second == null) return Enumerable.Empty<T>();
if (first == null) return second;
if (second == null) return first;
return f(first, second);
}
// Wrap the Intersect extension method in our Nullable wrapper
public static IEnumerable<T> NullableIntersect<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
// It'd be nice to write this as
//
// return first.NullableExtension<T>(second, IEnumerable<T>.Intersect );
//
return first.NullableExtension<T>(second, (a,b) => a.Intersect(b));
}
}
So, is there a way to pass in the IEnumerable<T>.Intersect extension method to NullableExtension directly rather than wrapping it in a lambda?
Edit
Because it is actually concise to pass in the Enumerable extension method, I removed the NullableIntersect (and other) methods and just call the nullable wrapper directly.
Also, as Anthony points out, the semantics of what an Empty enumerable should do is different depending on the extension method, i.e. Union versus Intersect. As such, I rename the NullableExtension method to IgnoreIfNull which better reflects the generic behavior.
public static class MyIEnumerableExtensions
{
// Generic wrappers to allow graceful handling of null values
public static IEnumerable<T> IgnoreIfNull<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
{
if (first == null && second == null) return Enumerable.Empty<T>();
if (first == null) return second;
if (second == null) return first;
return f(first, second);
}
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
{
return f(first ?? Enumerable.Empty<T>(), second ?? Enumerable.Empty<T>());
}
}
// Usage example. Returns { 1, 4 } because arguments to Union and Intersect are ignored
var items = new List<int> { 1, 4 };
var output1 = items.IgnoreIfNull(null, Enumerable.Union).IgnoreIfNull(null, Enumerable.Intersect);
// Usage example. Returns { } because arguments to Union and Intersect are set to empty
var output2 = items.EmptyIfNull(null, Enumerable.Union).EmptyIfNull(null, Enumerable.Intersect);
Intersectis defined within static classEnumerable. You can pass it into your method like belowNote: You might be concerned about the behavior of your logic in the case of a null sequence. For example, in the case of
You have defined it such that
outputcontains{1, 4}(the elements ofsecond). I might expectfirstto instead be treated as an empty sequence, and an intersection withsecondwould result in an empty sequence. Ultimately, that’s for you to decide the behavior you desire.