2009-05-01 166 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); 
    } 
} 
相關問題