針對 Type 類別在泛型處理上的不足,提供實用擴展方法集:
public static bool IsNullableType(this Type type)
=> type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
public static Type GetNonNullableType(this Type type)
=> IsNullableType(type) ? type.GetGenericArguments()[0] : type;
public static bool IsEnumerableType(this Type type)
=> FindGenericType(typeof(IEnumerable<>), type) != null;
public static Type GetElementType(this Type type) {
var t = FindGenericType(typeof(IEnumerable<>), type);
return t != null ? t.GetGenericArguments()[0] : type;
}
public static bool IsKindOfGeneric(this Type type, Type definition)
=> FindGenericType(definition, type) != null;
public static Type FindGenericType(this Type definition, Type type) {
while (type != null && type != typeof(object)) {
if (type.IsGenericType && type.GetGenericTypeDefinition() == definition)
return type;
if (definition.IsInterface)
foreach (var iface in type.GetInterfaces())
if (FindGenericType(definition, iface) != null) return type;
type = type.BaseType;
}
return null;
}
Assert.IsTrue(typeof(int?).IsNullableType());
Assert.AreEqual(typeof(int), typeof(int?).GetNonNullableType());
Assert.IsTrue(typeof(List<string>).IsEnumerableType());
Assert.AreEqual(typeof(int), typeof(List<int>).GetElementType());
Assert.IsTrue(typeof(List<string>).IsKindOfGeneric(typeof(IEnumerable<>)));
原碼源自內部庫,方法名未體現「Generic」語意(如 IsEnumerableType 實為檢查泛型集合),建議改名並加入契約式檢查,避免傳入非預期型別產生難以預料結果。