2009-02-09 18 views
20

Sto sviluppando un'applicazione in cui è necessario richiamare un metodo di una classe generica e non mi interessa il tipo effettivo delle istanze. Qualcosa come il seguente codice Java:Qual è l'equivalente dei caratteri jolly Java nei generici C#

public class Item<T>{ 
    private T item; 

    public doSomething(){...} 
} 

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

A quel tempo ero in fretta, così ho risolto il mio problema definendo un'interfaccia con i metodi di cui avevo bisogno per invocare e ha reso la classe generica attuarla.

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(); 
} 

Questa soluzione funziona bene, ma mi piacerebbe sapere qual è il modo corretto per ottenere lo stesso comportamento.

EDIT:

Ho dimenticato di riferimento che il chiamante di processItems non conosce i tipi effettivi. In realtà l'idea era che l'array passato come argomento a processItems potesse contenere tipi combinati. Dal momento che non è possibile avere un tale array in .Net, l'uso di una classe base o di una interfaccia non generica sembra essere l'unico modo.

risposta

25

Il modo normale per farlo sarebbe quello di rendere il metodo generico:

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

Supponendo che il chiamante conosce il tipo, inferenza di tipo dovrebbe significare che non c'è bisogno di specificare in modo esplicito. Ad esempio:

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

Detto questo, creando un'interfaccia non generica che specifica le operazioni di tipo agnostico può essere utile pure. Dipenderà molto dal tuo caso d'uso esatto.

+0

Blargh, pochi secondi troppo presto. : P –

+0

Sì, picchia anche me. Puoi modificare con un esempio del chiamante, però? –

+0

solo 'ProcessItems (dati);' –

1

Non è possibile omettere i parametri di tipo nell'implementazione generica .NET; questo è di design. In realtà, ciò può essere ottenuto solo in Java a causa dell'implementazione basata sulla cancellazione di tipo.

È possibile utilizzare solo un'interfaccia non generica di base (si pensi a IEnumerable<T> e IEnumerable).

0

Oltre al post di Jon. rendendo il metodo generico (un modello) nega il requisito per questo tipo di funzionalità (utilizzando <? >). Puoi sempre inserire un tipo in una classe/funzione generica e nei casi in cui non sai di quale tipo avrai bisogno puoi anche rendere generico il metodo/classe incriminato ... in definitiva l'utente deve fornire un tipo quando chiama tale funzione o utilizzare una classe generica, affinché il codice sia in grado di compilare ... altrimenti si otterranno alcuni errori del compilatore.

3

Vedo che si desidera richiamare solo un metodo senza parametri ... c'è già un contratto per questo: Action.

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

Cliente:

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

ho lottato con lo stesso problema quando si trattava di roba porting da Java, dove ho avuto costrutti come

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

Per fortuna si trasforma che un ICollection generico è anche un ICollection non generico e se qualcuno ha bisogno di trattare gli elementi in esso come oggetti puri è ancora possibile:

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

In questo modo, poiché non ci interessa il tipo effettivo di elementi nella raccolta, tutto ciò che otteniamo qui sono oggetti. Una nota qui: se la raccolta conteneva tipi primitivi (int o byte per esempio), allora calci di autoboxing in cui potrebbe introdurre penalità di prestazioni.

Problemi correlati