Jon Wong
Jon Wong

Reputation: 51

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

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?

Upvotes: 4

Views: 4705

Answers (3)

Hugo Moura
Hugo Moura

Reputation: 1

A method that I get a generic parameter (with the restriction of being a class because I will create a instance of this type). Then I define a default object at runtime, and check if the object received by parameter is null, if the object is null I return the object that was instantiated at runtime otherwise return the object itself passed by parameter.

I hope that helps

    public static T EmptyIfNull<T>(this T obj) where T : class
    {           
        var objNotNull = Activator.CreateInstance(typeof(T));

        if (obj == null)
            return objNotNull as T;

        return obj;
    }

Unit Test :

enter image description here

Upvotes: 0

Rob
Rob

Reputation: 27357

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

Upvotes: 10

Alberto Monteiro
Alberto Monteiro

Reputation: 6219

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>();
}

Upvotes: 4

Related Questions