2016-01-21 57 views
1

我知道這很可能是一個涉及泛型的簡單問題,或者很可能只是一個大「不」的整體,但我很好奇,看看我能否實現這個目標。創建一個方法來處理所有類型的IEnumerable(在設計運行時未知類型)

我試圖創建一個方法,需要在object,如果object是一個枚舉類型,將它傳遞給一個方法,可以在任何種類的枚舉上工作,但我越來越卡住。

我目前對於發生在一個對象方法的代碼看起來像下面這樣:

private void MyMethod() 
{ 
    Dictionary<string, object> MyVals = new Dictionary<string,object>(); 

    ... fill the MyVals dictionary ... 

    object x = MyVals["Val_1"]; 
    Type type = x.GetType(); 

    // Check if we have a series of values rather than a single value 
    if (type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type)) 
     Test(x); 
} 

然後,我以爲我可以寫東西類似下面的方法簽名爲我Test之一方法:

1.寫入它,就好像它是一個IEnumerable對象的:

private void Test(IEnumerable<object> MyEnumeration) 

嘗試過通過調用它:

Test((IEnumerable<object>)x); 

信息運行時錯誤,它不能從IEnumerable<int>轉換爲IEnumerable<object>

2.使用try泛型:

private void Test<T>(IEnumerable<T> MyEnumeration) 

打過電話它通過:

Test(x); 

導致簽名爲錯誤/無效參數的設計時錯誤。

或通過:

Test<type>(x); 

導致設計時錯誤的類型或命名空間type找不到。


這怎麼能做到或者它只是不好的編程習慣,有更好的方法來做到這一點?

謝謝!

+1

沒有理由無論是從看簽名失敗。然而,「既沒有作用」也不能解釋正在發生的事情,這使得這很難解決。當你嘗試這些時,什麼具體不起作用,一般來說,Test方法試圖完成什麼? –

+1

夠了,@TravisJ。讓我更新我的問題... –

+1

問題更新與我的嘗試 - 希望使(至少一點)更有意義。 –

回答

2

問題是與此代碼:

if (type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type)) 
    Test(x); 

你現在知道x是一個IEnumerable,但是當編譯器確定其方法簽名是兼容它仍然視爲object

如果你這樣做:

if (type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type)) 
{ 
    IEnumerable asEnumerable = (IEnumerable)x; 
    Test(asEnumerable); 
} 

然後,它可以傳遞給

void Test(IEnumerable t) 
{ 
} 

或者,如果你真的想用IEnumerable<object>

if (type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type)) 
{ 
    IEnumerable<object> asEnumerable = ((IEnumerable)x).Cast<object>(); 
    Test(asEnumerable); 
} 

而且,如果你想要一個IEnumerable<T>,看到Jon Skeet的answer到一個不同的問題。

+0

@TravisJ正確。我只是解決選項之一。你需要喬恩Skeet選項二:http://stackoverflow.com/questions/812673/convert-cast-ienumerable-to-ienumerablet –

+0

是的,其實你至少包括IEnumerable 用法的選項,所以我刪除了我的評論。我同意使用Jon Skeet建議的類型推斷方法是在進行類型推斷調用時遇到問題的最佳方法。 –

+0

謝謝! - 有效!!!! –

0

這有一個不好的代碼氣味,所以我會詳細說明你實際上想做什麼,也許有人可以幫忙。您的運行時錯誤是由於您擁有的集合其實不是IEnumerable [對象],而是IEnumberable [int]。你必須先打電話給.Cast。 所以這將是一個雙重演員。

Test(((IEnumerable<int>)x).Cast<object>); 

此外,這有一個可怕的代碼氣味。你應該詳細說明數據如何進入,我相信有人可以幫助你。

0

您應該創建兩個Test()方法的重載。一個會處理IEnumerable,另一個處理IEnumerable<T>爲什麼你需要方法超負荷?由於IEnumerables不是通用的IEnumerable<T>並且在運行時您不會知道使用Cast的通用類型的類型object

下面是展示如何實現準確你在找什麼樣:

public void MyMethod() 
{ 
    // Sample object with underlying type as IEnumerable 
    object obj1 = new ArrayList(); 

    // Sample object with underlying type as IEnumerable & IEnumerable<T> 
    object obj2 = (IList<string>)new List<string>(); 

     if (typeof(IEnumerable).IsAssignableFrom(obj1.GetType())) 
     { 
      if (!obj1.GetType().IsGenericType) 
      { 
       // Handles case of IEnumerable 
       Test((IEnumerable)obj1); 
      } 
      else 
      { 
       // Handles case of IEnumerable<T> 
       InvokeGenericTest(obj2); 
      } 
     } 
} 

public void Test(IEnumerable source) 
{ 
    Console.WriteLine("Yes it was IEnumerable."); 
} 


public void Test<T>(IEnumerable<T> source) 
{ 
    Console.WriteLine("Yes it was IEnumerable<{0}>.", typeof(T)); 

    // Use linq with out worries. 
    source.ToList().ForEach(x => Console.WriteLine(x)); 
} 

/// <summary> 
/// Invokes the generic overload of Test method. 
/// </summary> 
/// <param name="source"></param> 
private void InvokeGenericTest(object source) 
{ 
    Type t = source.GetType(); 

    var method = this.GetType().GetMethods().Where(x => x.IsGenericMethod && x.Name == "Test").First(); 

    var genericMethod = method.MakeGenericMethod(t.GenericTypeArguments.First()); 
    genericMethod.Invoke(this, new object[] { source }); 
} 
相關問題