我想要通用方法返回传递类型的默认值,但对于集合类型,我想获得空集合而不是null,例如:
GetDefault<int[]>(); // returns empty array of int's
GetDefault<int>(); // returns 0
GetDefault<object>(); // returns null
GetDefault<IList<object>>(); // returns empty list of objects
我开始编写的方法如下:
public static T GetDefault<T>()
{
var type = typeof(T);
if(type.GetInterface("IEnumerable") != null))
{
//return empty collection
}
return default(T);
}
如何完成它?
修改 如果有人希望获得某种类型的默认值,基于类型实例而不是类型标识符,可以使用下面的结构,即:
typeof(int[]).GetDefault();
实施内部基于@ 280Z28答案:
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);
}
}
答案 0 :(得分:11)
您可以使用静态构造函数的魔力来有效地执行此操作。要在代码中使用默认值,只需使用Default<T>.Value
即可。在申请期间,只会对任何给定类型T
评估该值。
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;
}
}
}
答案 1 :(得分:9)
IList<object>
不是集合类型,它是一个接口。您可以返回几十个可能的课程。
如果传入实际的集合类型,则可以执行以下操作:
public static T GetDefault<T>() where T : new
{
if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
{
return new T();
}
return default(T);
}
GetDefault<List<object>>();
要处理两个空集合和没有默认构造函数的null
类型值,您可以这样做:
public static T GetDefault<T>()
{
if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
{
if (typeof(T).IsGenericType)
{
Type T_template = typeof(T).GetGenericTypeDefinition();
if (T_template == typeof(IEnumerable<>))
{
return (T)Activator.CreateInstance(typeof(Enumerable).MakeGenericType(typeof(T).GetGenericArguments()));
}
if (T_template == typeof(IList<>))
{
return (T)Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(T).GetGenericArguments()));
}
}
try {
return Activator.CreateInstance<T>();
}
catch (MissingMethodException) {} // no default exists for this type, fall-through to returning null
}
return default(T);
}