2009-05-01 130 views
44

我有一个类(一个Web控件),它具有IEnumerable类型的属性,并希望使用LINQ参数。转换/投射IEnumerable到IEnumerable <T>

有没有办法通过反射投射/转换/调用IEnumerable <T>不知道编译时的类型?

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) {} 

回答

56

Method2真正关心它得到什么类型的?如果没有,你可能只需要调用Cast<object>()

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<type>调用将失败。例如,如果第一个元素碰巧是一个字符串,但是源代码是List<object>,则会出现问题。

8

你可能想重构代码使用IEnumerable.Cast<T>

使用方法如下:

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

需要在编译时的类型。同样的问题。 – andleer 2009-05-01 18:47:39

+0

这是正确的。 Method2也是如此。你总是可以使用IEnumerable ... – 2009-05-01 18:52:58

2

这是几年后,但我解决了List<Object>问题。

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 }); 
    } 
} 
3

在.NET 4中,你可以将它传递给方法之前只投sourcedynamic。这将导致正确的泛型重载在运行时没有任何丑陋的反射代码来解决:

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

    if (enumerator.MoveNext()) 
    { 
     Method2((dynamic)source); 
    } 
} 

与乔恩的第二个解决方案,这将只有当你的源实际上是一个IEnumerable<T>工作。如果是一个普通的IEnumerable,那么你就需要创建它转换为正确的IEnumerable<T>类型,如在下述溶液中的另一种方法:

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); 
    } 
} 
相关问题