Reputation: 51
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
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 :
Upvotes: 0
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
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