[英]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.