Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# EmptyIfNull extension for any IEnumerable to return empty derived type

Tags:

c#

Assuming nulls and empty collections are equivalent, I'm trying to write an extension method for IEnumerable types to return empty collections of the derived type instead of null. This way I don't have to repeat null checks all over the place, and I don't get an IEnumerable back that I have to cast.

e.g.

List<Foo> MethodReturningFooList()
{
...
}

Foo[] MethodReturningFooArray()
{
...
}

void Bar()
{
    List<Foo> list = MethodReturningFooList().EmptyIfNull();
    Foo[] arr = MethodReturningFooArray().EmptyIfNull();
}

public static class Extension
{
    public static T EmptyIfNull<T>(this T iEnumerable)
        where T : IEnumerable, new()
    {
        var newTypeFunc = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
        return iEnumerable == null ? newTypeFunc() : iEnumerable;
    }
}

This extension seems to work, but does anyone see any pitfalls?

like image 672
Jon Wong Avatar asked Oct 18 '25 15:10

Jon Wong


2 Answers

Yes, it will break in this case:

IEnumerable<int> test = null;
var result = test.EmptyIfNull();

You can solve it like this:

public static class Extension
{
    public static List<T> EmptyIfNull<T>(this List<T> list)
    {
        return list ?? new List<T>();
    }
    public static T[] EmptyIfNull<T>(this T[] arr)
    {
        return arr ?? new T[0];
    }
    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> enumerable)
    {   
        return enumerable ?? Enumerable.Empty<T>();
    }
}

You'll need overloads to make sure you're returning the same collection type (as you were before).

Here's an example of a case that can't work by returning the same collection type:

public abstract class MyAbstractClass : IEnumerable<int>
{
    private List<int> tempList = new List<int>();
    public IEnumerator GetEnumerator()
    {
        return tempList.GetEnumerator();
    }
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        return tempList.GetEnumerator();
    }
}

MyAbstractClass myClass = null;
MyAbstractClass instance = myClass.EmptyIfNull();

There's no way we can return a MyAbstractClass here without knowing about subclasses. And with a null reference, that's not possible without guessing. Further, what happens when classes do not have a default constructor? Getting into dangerous territory.

You'll need to either have a catch-all IEnumerable<T> return, and have the user cast it, or provide overloads as I've shown above

like image 80
Rob Avatar answered Oct 21 '25 05:10

Rob


I just should improve this like that

public static class Extension 
{ 
    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> iEnumerable) 
    { 
        return iEnumerable ?? Enumerable.Empty<T>();
    }
}

Or better with C# 6

public static class Extension 
{ 
    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> iEnumerable) 
        => iEnumerable ?? Enumerable.Empty<T>();
}
like image 26
Alberto Monteiro Avatar answered Oct 21 '25 06:10

Alberto Monteiro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!