我有一个检查类型是否为泛型的方法,然后检查GenericTypeDefinition是否为IEnumerable<>
。
static Type GetEnumerableType(Type type)
{
if(type.IsGenericType) {
var genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(IEnumerable<>)) {
return type.GetGenericArguments()[0];
}
}
return null;
}
如果它是IEnumerable,就像魅力一样。如果GenericTypeDefinition为IList<>
或List<>
则不起作用。我试过了..
typeof(IEnumerable<>).IsAssignableFrom(genericTypeDefinition)
..没有成功。当然,必须有更好的方法来链接其他语句吗?
答案 0 :(得分:12)
您可以使用GetInterfaces
检查某个类型是否实现IEnumerable<>
,如此
Type type = new List<string>().GetType();
if (type.IsGenericType)
{
var genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition.GetInterfaces()
.Any( t => t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
return type.GetGenericArguments()[0];
}
}
答案 1 :(得分:7)
我结束了对一般物体处理的深入研究,发现这种方式比任何原始假设更复杂。这是我现在使用的方法:
/// <summary>Check whether the specified type is enumerable.</summary>
/// <param name="type">The type.</param>
/// <param name="underlyingType">IEnumerable{int} would be int</param>
/// <param name="excludeString">
/// [OPTIONAL] if set to <c>true</c> [exclude string]. Strings are enumerable as char[]
/// this is likely not something you want. Default is true (string will return false)
/// </param>
/// <returns><c>true</c> supplied type is enumerable otherwise <c>false</c></returns>
public static bool IsEnumerable(this Type type, out Type underlyingType,
bool excludeString = true)
{
underlyingType = null;
if (type.IsEnum || type.IsPrimitive || type.IsValueType) return false;
if (excludeString && type == typeof(string)) return false;
if (type.IsGenericType)
{
if (type.IsTypeDefinitionEnumerable() ||
type.GetInterfaces()
.Any(t => t.IsSelfEnumerable() || t.IsTypeDefinitionEnumerable()))
{
underlyingType = type.GetGenericArguments()[0];
return true;
}
}
//direct implementations of IEnumerable<T>, inheritance from List<T> etc
var enumerableOrNull = type.GetInterfaces()
.FirstOrDefault(t => t.IsTypeDefinitionEnumerable());
if (enumerableOrNull == null) return false;
underlyingType = enumerableOrNull.GetGenericArguments()[0];
return true;
}
//
private static bool IsSelfEnumerable(this Type type)
{
bool isDirectly = type == typeof(IEnumerable<>);
return isDirectly;
}
private static bool IsTypeDefinitionEnumerable(this Type type)
{
bool isViaInterfaces = type.IsGenericType &&
type.GetGenericTypeDefinition().IsSelfEnumerable();
return isViaInterfaces;
}
测试此解决方案:
安装包NUnit -Version 2.6.4
应该安装包
[Test]
public void List_is_enumerable()
{
var sut = new List<int>();
Type underlyingType;
var result = sut.IsEnumerable(out underlyingType);
result.ShouldBeTrue();
underlyingType.ShouldBe(typeof(int));
}
//
[Test]
public void Yield_return_is_enumerable()
{
var sut = Yielded();
Type underlyingType;
var result = sut.IsEnumerable(out underlyingType);
result.ShouldBeTrue();
underlyingType.ShouldBe(typeof(int));
}
private IEnumerable<int> Yielded()
{
for (int i = 0; i < 3; i++)
{
yield return i;
}
}
//
[Test]
public void int_is_not_an_enumerable()
{
var sut = 5;
Type underlyingType;
var result = sut.IsEnumerable(out underlyingType);
result.ShouldBe(false);
underlyingType.ShouldBeNull();
}
[Test]
public void object_is_not_an_enumerable()
{
var sut = new { foo = 1};
Type underlyingType;
var result = sut.IsEnumerable(out underlyingType);
result.ShouldBe(false);
underlyingType.ShouldBeNull();
}
为后代举行。这不符合原始问题,但对会员来说显然很有用。
public static bool IsA<T>(this Type type)
{
return typeof (T).IsAssignableFrom(type);
}