2009-02-09 12 views
20

Estoy desarrollando una aplicación donde necesito invocar un método de una clase genérica y no me importan las instancias del tipo real. Algo así como el siguiente código de Java:¿Cuál es el equivalente de comodines de Java en genéricos C#

public class Item<T>{ 
    private T item; 

    public doSomething(){...} 
} 

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

En ese momento yo estaba en una prisa, así que resolvió mi problema definiendo una interfaz con los métodos que necesitaba para invocar e hizo la clase genérica en práctica.

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

Esta solución funciona bien, pero me gustaría saber cuál es la forma correcta para lograr el mismo comportamiento.

EDIT:

me olvidó referirse a que la persona que llama de processItems no conoce los tipos reales. En realidad, la idea era que el conjunto pasado como argumento a processItems podría contener tipos entremezclados. Como no es posible tener una matriz de este tipo en .Net, el uso de una clase base o interfaz no genérica parece ser la única forma.

Respuesta

25

La forma normal de hacer esto sería hacer el método genérico:

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

Suponiendo que la persona que llama sabe el tipo, la inferencia de tipos debería significar que no tienen que especificar explícitamente. Por ejemplo:

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

Una vez dicho esto, la creación de una interfaz no genérico que especifica las operaciones de tipo-agnóstico puede ser útil también. Dependerá mucho de su caso de uso exacto.

+0

Blargh, unos segundos antes de tiempo. : P –

+0

Sí, vencerme también. Sin embargo, ¿puedes editar con un ejemplo de la persona que llama? –

+0

solo 'ProcessItems (data);' –

1

No hay manera de que pueda omitir los parámetros de tipo en la implementación genérica de .NET; esto es por diseño. De hecho, esto solo se puede lograr en Java debido a su implementación basada en el borrado de tipos.

Solo puede usar una interfaz base no genérica (piense en IEnumerable<T> y IEnumerable).

0

Además de la publicación de Jon. hacer que el método genérico (una plantilla) niegue el requisito para este tipo de funcionalidad (usando <? >). Siempre puede enviar un tipo a una clase/función genérica y, en los casos en que no sabe qué tipo necesitará, también puede hacer que el método/clase ofensivo sea genérico ... en última instancia, el usuario debe proporcionar un tipo al llamar tal función o usando una clase genérica, para que el código sea capaz de compilar ... de lo contrario, obtendrá algunos errores del compilador.

3

Veo que solo quiere invocar algún método sin parámetros ... ya hay un contrato para eso: 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

He estado luchando con el mismo problema cuando se trataba de portar cosas de Java donde he tenido construcciones como

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

Afortunadamente se convierte que un ICollection genérico es también un ICollection no genérico y si alguien necesita para el tratamiento de los elementos en los mismos objetos puros todavía es posible:

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

De esa manera, ya que no importa el tipo real de los elementos de la colección todo lo que tenemos aquí son objetos. Una nota aquí: si la colección tenía tipos primitivos (int o byte, por ejemplo), entonces se activa el autoboxing, lo que podría introducir una penalización de rendimiento.

Cuestiones relacionadas