【问题标题】:How can I see if GenericTypeDefinition implements IEnumerable<>如何查看 GenericTypeDefinition 是否实现 IEnumerable<>
【发布时间】:2011-01-20 03:30:25
【问题描述】:

我有一个方法可以检查类型是否为泛型,然后检查 GenericTypeDefinition 是否为 IEnumerable&lt;&gt;

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&lt;&gt;List&lt;&gt; 它不起作用。我试过了。。

typeof(IEnumerable<>).IsAssignableFrom(genericTypeDefinition)

..没有成功。当然必须有比链接 else 语句更好的方法?

【问题讨论】:

  • 我认为 Stan R. 的解决方案可能大致是您正在寻找的,但您的问题未充分说明。您只关心泛型类型,还是可能还关心非泛型类型(例如实现IEnumerable&lt;string&gt; 的非泛型类型)?
  • 目前我只关心泛型类型,但你说得很好。

标签: c# generics types


【解决方案1】:

我结束了对一般对象处理的深入研究,发现这种方式比任何原始假设都复杂。这是我现在使用的方法:

/// <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;
}

此解决方案经过测试:

Install-Package 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);
}

【讨论】:

  • 它并没有解决问题。而且,是的,我也经常弄错 IsAssignableFrom 方法,但我认为这里不是这样。
  • 带有if(type.IsA&lt;IEnumerable&lt;&gt;&gt;) { 的编辑代码不会编译,因为它需要一个类型参数。
  • 我会成为一个挑剔的人,并将该方法称为“IsOfType”。为什么?因为“Is a IEnumerable”听起来不正确(应该是 Is an,但它变得非常棘手 :P) 不过说真的,我要窃取这个扩展方法。我喜欢!
  • OP 没有向后使用IsAssignableFrom,他只是在open generic type 上使用它。此外,根据您的代码编写方式,type.IsA&lt;IEnumerable&lt;&gt;&gt;() 将在所有类型中返回 false。
  • 完全重写的答案
【解决方案2】:

您可以使用GetInterfaces 来检查一个类型是否像这样实现IEnumerable&lt;&gt;

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];
    }
}

【讨论】:

  • 此方法将错误地为MyList : List&lt;string&gt;yield return @string 返回false,因为MyList 和yield 生成的状态机不是泛型类且IsGenericType 为false
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 2012-07-03
  • 2014-12-20
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
相关资源
最近更新 更多