【问题标题】:How to check if a type T of a generic method is IEnumerable<> and loop it?如何检查泛型方法的类型 T 是否为 IEnumerable<> 并循环它?
【发布时间】:2012-09-20 21:23:56
【问题描述】:

我想做这样的事情

void DoSomething<T>(T param)
{
    if param is IEnumerable<?>
    {
        loop param and do stuff
    }
}

我不知道在问号的位置做什么。这有可能吗?

【问题讨论】:

标签: c# generics


【解决方案1】:

您必须检查该类实现的每个接口的开放泛型类型,如下所示:

bool implements = typeof(T).GetInterfaces().Where(t => t.IsGenericType && 
    t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).Any();

这将允许您在不知道T 是什么类型的情况下确定一个类型是否实现了IEnumerable&lt;T&gt;。请记住,该类型可以多次实现IEnumerable&lt;T&gt;

如果您只是想要IEnumerable&lt;T&gt; 的类型参数的类型序列,您可以将上述查询更改为;

IEnumerable<Type> types = typeof(T).GetInterfaces().
    Where(t => t.IsGenericType && 
        t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).
    Select(t => t.GetGenericArguments()[0]);

【讨论】:

  • 一个类型实现IEnumerable&lt;T&gt; 多次确实是一种可怕的类型。
【解决方案2】:

您正在寻找的是:

if (T is IEnumerable) { .. }

但如果您希望 T 始终是 IEnumerable,您可以这样做:

void DoSomething<T>(T param) where T : IEnumerable
{
    foreach (var t in param) { ... }
}

或检查 IEnumerable 中的值的类型:

public void DoSomething<T,U>(T val) where T : IEnumerable<U>
{
    foreach (U a in val)
    {
    }
}

不用担心自己检查,编译器会为你做,这是拥有静态类型系统和编译器的好处之一 :)

【讨论】:

  • 我认为他实际上是在尝试检查特定类型的 IEnumerable,而不仅仅是一般的 IEnumerable。问题下评论中的链接处理该场景
  • 好点。我会用那个场景来完成答案,谢谢。
  • 感谢您的好评。问题是我不希望 T 一直是 IEnumerable 。事实上,我已经有一个方法void ProcessList&lt;T&gt;(IEnumerable&lt;T&gt; list),如果参数是IEnumerable,我想在DoSomething() 中重用它。
  • @mbqt 应该注意的是,IEnumerable&lt;T&gt; 的所有实现都实现了IEnumerable(它毕竟是从它派生的)但是IEnumerable 的实现是保证的实现IEnumerable&lt;T&gt;,做出这样的假设是不正确的。
  • 我意识到这是一个旧帖子,但是(T is IEnumerable)不仅无法编译,而且不正确。 (typeof(T) is IEnumerable) 编译,但仍然是错误的,因为 typeof(T) 最终是一个对象。这样做的正确方法似乎是: typeof(IEnumerable).IsAssignableFrom(typeof(T))
【解决方案3】:

有几种方法:

void DoSomething<T>(T param)
{
    if (param is IEnumerable)
    {
        foreach (var item in (IEnumerable)param)
        {
            // Do something
        }
    }
}

void DoSomething<T>(T param)
{
    if (param is IEnumerable<string>)
    {
        foreach (var item in (IEnumerable<string>)param)
        {
            // Do something
        }
    }
}

void DoSomething<T,TItem>(T param)
{
    if (param is IEnumerable<TItem>)
    {
        foreach (var item in (IEnumerable<TItem>)param)
        {
            // Do something
        }
    }
}

【讨论】:

  • 最佳实践是使用as 而不是is-plus-direct-cast,因为as 只进行一次昂贵的运行时类型检查,而 is-plus-direct- cast 做了两次。
猜你喜欢
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
  • 2016-05-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多