2009-02-09 41 views
20

我正在開發一個應用程序,我需要調用泛型類的方法,而且我不關心實例的實際類型。類似下面的Java代碼:什麼是C#泛型中的Java通配符相當於

public class Item<T>{ 
    private T item; 

    public doSomething(){...} 
} 

... 
public void processItems(Item<?>[] items){ 
for(Item<?> item : items) 
    item.doSomething(); 
} 

當時我是在趕時間,所以我定義與我需要調用的方法的接口,解決了我的問題,並提出了通用類實現它。

public interface IItem 
{ 
    void doSomething(); 
} 

public class Item<T> : IItem { 
    private T item; 

    public void doSomething(){...} 
} 

... 
public void processItems(IItem[] items) 
{ 
foreach(IItem item in items) 
    item.doSomething(); 
} 

此變通辦法正常工作,但我想知道什麼是要實現相同的行爲的正確方法。

編輯:

我忘了提及的是的processItems調用者不知道實際的類型。實際上這個想法是,作爲參數傳遞給processItems的數組可能包含混合類型。由於在.Net中不可能有這樣的數組,因此使用非泛型基類或接口似乎是唯一的方法。

回答

25

正常的方式做,這將是使該方法一般:

public void ProcessItems<T>(Item<T>[] items) { 
    foreach(Item<T> item in items) 
    item.DoSomething(); 
} 

假設呼叫者知道的類型,類型推斷應該意味着他們沒有顯式指定它。例如:

Item<int> items = new Item<int>(); // And then populate... 
processor.ProcessItems(items); 

儘管如此,創建一個指定類型無關操作的非通用接口也是有用的。這將非常依賴於你的確切用例。

+0

Blargh,幾秒鐘過早。 :P – 2009-02-09 11:25:53

1

您無法在.NET通用實現中省略類型參數;這是設計。事實上,這隻能在Java中實現,因爲它基於類型擦除的實現。

您只能使用基本非通用接口(請考慮IEnumerable<T>IEnumerable)。

0

繼續Jon的文章。使方法通用(模板)否定這種功能的要求(使用<?>)。你總是可以將一個類型提供給一個通用的類/函數,並且在你不知道你需要什麼類型的情況下,你也可以製作違規方法/類的通用類型......最終用戶在調用時必須提供一個類型這樣的函數或使用泛型類的代碼,以便能夠編譯...否則您將得到一些編譯器錯誤。

3

我看到你只想調用一些沒有參數的方法......已經有一個合約:Action

public void processItems(IEnumerable<Action> actions) 
{ 
    foreach(Action t in actions) 
    t(); 
} 

客戶:

List<Animal> zoo = GetZoo(); 
List<Action> thingsToDo = new List<Action>(); 
// 
thingsToDo.AddRange(zoo 
    .OfType<Elephant>() 
    .Select<Elephant, Action>(e => e.Trumpet)); 
thingsToDo.AddRange(zoo 
    .OfType<Lion>() 
    .Select<Lion, Action>(l => l.Roar)); 
thingsToDo.AddRange(zoo 
    .OfType<Monkey>() 
    .Select<Monkey, Action>(m => m.ThrowPoo)); 
// 
processItems(thingsToDo); 
0

我一直在掙扎了同樣的問題,當它來到從Java移植的東西在那裏我已經構造,如

if (o instanceof Collection<?>) doSoemthing((Collection<?>)o); 

好在事實證明一個通用的ICollection也是一個非泛型的ICollection,如果有人需要將其中的元素作爲純對象處理,它仍然是可能的:

if (o is ICollection) DoSomething((ICollection)o); 

這樣,因爲我們不關心集合中元素的實際類型,所以我們在這裏得到的是對象。 這裏有一個註釋:如果集合保存了原始類型(例如int或者byte),那麼可能會引入性能損失的自動裝配踢。