2012-07-06 30 views
8

He simplificado y reproducido mi problema en el siguiente código. El error que estoy recibiendo es: Argumento 1: no se puede convertir de 'System.Collections.ObjectModel.Collection' a 'System.Collections.ObjectModel.CollectionC# Pasando una colección como una colección de interfaces

Algunos antecedentes de las decisiones de diseño que llevaron a este problema: Tengo creó un servicio web para tratar con "IFruit", pero debido a la naturaleza de SOAP y enlaces de punto final como los entiendo, he creado métodos con implementaciones explícitas de IFruit. En la capa empresarial, crear un método separado para cada implementación específica de fruta generaría en primer lugar una gran cantidad de código duplicado y, en segundo lugar, acoplar la capa de negocio y servicio lo suficiente como para aceptar nuevos tipos de IFruit en el servicio web más tarde. en la capa de negocios (agregando otra copia de código redundante). Este diseño es uno que he implementado con éxito utilizando Java en el pasado, pero las interfaces C# parecen ser lo suficientemente diferentes como para arrojarme. Por favor avise.

public interface IFruit{ 
    public string TakeBite(); 
} 

public Apple : IFruit{ 
    public string TakeBite(){ 
     return "tasty bite of apple"; 
    } 
} 

public void EatFruit(Collection<IFruit> fruits){ 
    foreach(var fruit in fruits){ 
     Console.WriteLine(fruit.TakeBite()); 
    } 
} 

public void EatApples(Collection<Apple> apples){ 
    this.EatFruit(apples); 
} 

Respuesta

9

trate de cambiar su método de EatFruit para aceptar IEnumerable<IFruit>

public void EatFruit(IEnumerable<IFruit> fruits) 
{ 
    foreach (var fruit in fruits) 
    { 
     Console.WriteLine(fruit.TakeBite()); 
    } 
} 

La interfaz soporta IEnumerable<out T> covarianza ya que está marcado con el modificador out. Collection<T> no está marcado con dicho modificador.

+0

Gracias. Esto compila.Ahora para actualizar mis pruebas de unidad. – YouGotCSharpInMyJava

1

Eso se llama la covarianza.
Sin embargo, no es posible con colecciones mutables.

De lo contrario, podría escribir EatFruit

fruits.Add(new Orange()); 

.Net 4 es compatible con las interfaces de covarianza para reas de sólo, por lo que puede cambiarlo a IEnumerable<IFruit> y funcionará.

+0

¿Asumiendo que Orange implementa IFruit entonces hay un problema allí? – Charleh

+1

@Charleh: 'fruits' es _actually_ a' Colección '. No puede contener un 'Naranja'. – SLaks

+0

Pensé que dado que Fruit era una Colección que podría contener cualquier tipo que implementara IFruit? – Charleh

0

Aparte de usar IEnumerable podría escribir comprobar la colección (bit horrible pero debería funcionar):

public void EatApples(Collection<IFruit> fruit) 
    var col = new Collection<IFruit>(); 

    fruit.Where(x => x is Apple).ToList().ForEach(x => col.Add(x)); 

    this.EatFruit(col); 
} 

A pesar de que haría uso de IEnumerable en lugar - esto es sólo una opción si no se puede refactorizar: P

(que es como un tipo seguro como usted lo hace!)

+0

Eso haría 2x trabajos: crea una lista y luego agrega cada uno a la colección. Es mejor hacer: 'foreach (var x en fruit.OfType ()) {col.Add (x); } ' –

+0

Sí cierto - en ninguna parte dije que sería perfecto (¡y mencioné horrible allí también!): D – Charleh

0

solución simple:

public void EatApples(Collection<Apple> apples){ 
    this.EatFruit(
      new Collection<IFruit>(
       apples.Cast<IFruit>() 
     ) 
    ); 
} 

Mejor solución: use la covarianza introducida en C# 4: vea Kevin's respuesta

Cuestiones relacionadas