我深入研究了一般对象处理,发现这比任何原始假设都更为复杂。这是我现在使用的方法:
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;
}
}
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包 - 版本2.6.4
安装Shouldly包
[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);
}
IEnumerable<string>
的非通用类型)? - kvb