default(T) with empty collection instead of null
.net, c#
Solution
You can use the magic of a static constructor to do this efficiently. To use the default value in code, simply use `Default<T>.Value`. The value will only be evaluated for any given type `T` once for the duration of your application.
public static class Default<T>
{
private static readonly T _value;
static Default()
{
if (typeof(T).IsArray)
{
if (typeof(T).GetArrayRank() > 1)
_value = (T)(object)Array.CreateInstance(typeof(T).GetElementType(), new int[typeof(T).GetArrayRank()]);
else
_value = (T)(object)Array.CreateInstance(typeof(T).GetElementType(), 0);
return;
}
if (typeof(T) == typeof(string))
{
// string is IEnumerable<char>, but don't want to treat it like a collection
_value = default(T);
return;
}
if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
{
// check if an empty array is an instance of T
if (typeof(T).IsAssignableFrom(typeof(object[])))
{
_value = (T)(object)new object[0];
return;
}
if (typeof(T).IsGenericType && typeof(T).GetGenericArguments().Length == 1)
{
Type elementType = typeof(T).GetGenericArguments()[0];
if (typeof(T).IsAssignableFrom(elementType.MakeArrayType()))
{
_value = (T)(object)Array.CreateInstance(elementType, 0);
return;
}
}
throw new NotImplementedException("No default value is implemented for type " + typeof(T).FullName);
}
_value = default(T);
}
public static T Value
{
get
{
return _value;
}
}
}
Problem
I'd like to have generic method which returns default value for passed type, but for collection type I'd like to get empty collection instead of null, for example: ``` GetDefault<int[]>(); // returns empty array of int's GetDefault<int>(); // returns 0 GetDefault<object>(); // returns null GetDefault<IList<object>>(); // returns empty list of objects ``` The method I started to write is following: ``` public static T GetDefault<T>() { var type = typeof(T); if(type.GetInterface("IEnumerable") != null)) { //return empty collection } return default(T); } ``` How to complete it ? EDIT: If anyone would like get default value of some type, based on type instance instead of type identifier, this construction below can be used, i.e.: ``` typeof(int[]).GetDefault(); ``` The implementation is internally based on @280Z28 answer: ``` public static class TypeExtensions { public static object GetDefault(this Type t) { var type = typeof(Default<>).MakeGenericType(t); var property = type.GetProperty("Value", BindingFlags.Static | BindingFlags.Public); var getaccessor = property.GetGetMethod(); return getaccessor.Invoke(null, null); } } ```