【问题标题】:Convert / Cast IEnumerable to IEnumerable<T>将 IEnumerable 转换/强制转换为 IEnumerable<T>
【发布时间】:2009-05-01 18:44:21
【问题描述】:

我有一个具有 IEnumerable 类型属性的类(一个 Web 控件),并希望使用 LINQ 处理该参数。

有什么方法可以通过反射转换/转换/调用 IEnumerable 在编译时不知道类型?

Method void (IEnumerable source)
{
    var enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {
        var type = enumerator.Current.GetType();
        Method2<type>(source); // this doesn't work! I know!
    }
}

void Method2<T>(IEnumerable<T> source) {}

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    你的Method2 真的关心它得到什么类型吗?如果没有,您可以拨打Cast&lt;object&gt;()

    void Method (IEnumerable source)
    {
        Method2(source.Cast<object>());
    }
    

    如果您确实需要获得正确的类型,则需要使用反射。

    类似:

    MethodInfo method = typeof(MyType).GetMethod("Method2");
    MethodInfo generic = method.MakeGenericMethod(type);
    generic.Invoke(this, new object[] {source});
    

    这并不理想……特别是,如果源不是完全 IEnumerable&lt;type&gt;,那么调用将失败。例如,如果第一个元素恰好是一个字符串,但源是一个List&lt;object&gt;,你就会遇到问题。

    【讨论】:

    • 根据情况也可以使用OfType,只是指出来。另见:stackoverflow.com/questions/4015930/…
    • 这也是从 IQueryable 迁移到 IQueryable 的一种方法(适用于其他此类场景。)一旦你移动过来,你将能够调用和使用你期望的所有东西并且绝对需要。
    【解决方案2】:

    您可能希望重构代码以使用IEnumerable.Cast&lt;T&gt;

    像这样使用它:

    IEnumerable mySet = GetData();
    var query = from x in mySet.Cast<int>()
                where x > 2
                select x;
    

    【讨论】:

    • 在编译时需要类型。同样的问题。
    • 没错。 Method2也是如此。您总是可以转换为 IEnumerable...
    【解决方案3】:

    使用 .NET 4,您只需将 source 转换为 dynamic,然后再将其传递给方法。这将导致在运行时解决正确的泛型重载,而无需任何丑陋的反射代码:

    void Method(IEnumerable source)
    {
        var enumerator = source.GetEnumerator();
    
        if (enumerator.MoveNext())
        {
            Method2((dynamic)source);
        }
    }
    

    与 Jon 的第二个解决方案一样,这仅在您的源实际上是 IEnumerable&lt;T&gt; 时才有效。如果它是一个普通的IEnumerable,那么您需要创建另一个方法,将其转换为正确的IEnumerable&lt;T&gt; 类型,如下面的解决方案:

    IEnumerable<T> Convert<T>(IEnumerable source, T firstItem)
    {
        // Note: firstItem parameter is unused and is just for resolving type of T
        foreach(var item in source)
        {
            yield return (T)item;
        }
    }
    
    void Method(IEnumerable source)
    {
        var enumerator = source.GetEnumerator();
    
        if (enumerator.MoveNext())
        {
            dynamic firstItem = enumerator.Current;
            dynamic typedEnumerable = Convert(source, firstItem);
            Method2(typedEnumerable);
        }
    }
    

    【讨论】:

      【解决方案4】:

      这是几年后的事了,但我解决了List&lt;Object&gt; 问题。

      void Method(IEnumerable source)
      {
          var enumerator = source.GetEnumerator();
          if (enumerator.MoveNext())
          {
              MethodInfo method = typeof(MyClass).GetMethod("Method2");
              MethodInfo generic;
              Type type = enumerator.Current.GetType();
              bool sameType = true;
      
              while (enumerator.MoveNext())
              {
                  if (enumerator.Current.GetType() != type)
                  {
                      sameType = false;
                      break;
                  }
              }
      
              if (sameType)
                  generic = method.MakeGenericMethod(type);
              else
                  generic = method.MakeGenericMethod(typeof(object));
      
              generic.Invoke(this, new object[] { source });
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-07
        • 1970-01-01
        • 1970-01-01
        • 2012-02-24
        • 2018-08-04
        相关资源
        最近更新 更多