簡體   English   中英

創建一種方法來處理所有類型的IEnumerable(在設計運行時類型未知)

[英]Create a method to work on IEnumerable of all types (type unknown at design run-time)

我知道這很可能是一個涉及泛型的簡單問題,或者很可能只是一個很大的“不可以”,但是我很好奇我是否能解決這個問題。

我正在嘗試創建一個接受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.嘗試使用泛型:

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

嘗試通過以下方式調用它:

Test(x);

導致設計時錯誤,簽名不正確/參數無效。

或通過:

Test<type>(x);

導致設計時錯誤,即找不到類型或名稱空間type


怎么辦呢?或者這只是不好的編程習慣,還有更好的方法嗎?

謝謝!

問題在於此代碼:

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

您現在知道x是IEnumerable,但是當編譯器確定哪些方法簽名兼容時, x仍被視為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)對另一個問題的回答

這有一種不好的代碼味道,所以我會詳細說明您實際上想要做什么,也許有人可以提供幫助。 您的運行時錯誤是由於您所擁有的集合實際上不是IEnumerable [object]而是IEnumberable [int]而導致的。 您必須先致電.Cast。 因此,它將是雙重演員。

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

同樣,這具有可怕的代碼味道。 您應該詳細說明數據的輸入方式,我相信有人可以為您提供幫助。

您應該創建兩個Test()方法的重載。 一個將處理IEnumerable ,另一個將處理IEnumerable<T> 為什么需要方法重載? 因為IEnumerables不是通用的IEnumerable<T>並且在運行時您不會知道使用Cast on 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 });
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM