2009-03-16 14 views
12

Soy nuevo en interfaces y clases abstractas. Quiero crear un par de interfaces para definir los principales métodos y variables para los objetos de un sistema de carrito de compras. Entonces quiero crear clases abstractas que implementen las funciones centrales. La idea es que puedan ser utilizados por otras clases de maneras ligeramente diferentes para diferentes proyectos.¿Cómo puedo definir el tipo de devolución de un método de interfaz para que sea otra interfaz?

Éstos son mis (corte hacia abajo) interfaces:

public interface ICart 
{ 
    ... 
    List<ICartItem> CartItems { get; set; } 
} 

public interface ICartItem 
{ 
    int ProductId { get; set; } 
    int Quantity { get; set; } 
} 

Y aquí está mi clase abstracta de la compra (de nuevo, sólo muestra las líneas relevantes) que implementa Icart:

public abstract class Cart : ICart 
{ 

    private List<CartItem> _cartItems = new List<CartItem>(); 

    public List<CartItem> CartItems 
    { 
     get 
     { 
      return _cartItems; 
     } 
    } 
} 

Y mi CartItem clase que implementa ICartItem:

public abstract class CartItem : ICartItem 
{ 
    ... 
} 

Cuando intento compilar las clases obtengo un error m aying: 'Cart' no implementa el miembro de interfaz 'CartItems'. 'Cart.CartItems' no puede implementar 'ICart.CartItems' porque no tiene el tipo de retorno coincidente de System.Collections.Generic.List <ICartItem>.

Pensé que la idea aquí es que la interfaz puede ser implementada por varias clases que realizan las funciones centrales de diferentes maneras y agregan nuevos métodos, etc. ¿Por qué mi interfaz necesitaría saber qué clase se está utilizando realmente? , siempre y cuando esa clase realmente implemente la interfaz correctamente?

Respuesta

20

Necesitas genéricos de usuario en C# 2 para lograr que:

public interface ICart<T> where T : ICartItem 
{ 
    // ... 
    List<T> CartItems { get; set; } 
} 

public abstract class Cart : ICart<CartItem> 
{ 
    // ... 
    public List<CartItem> CartItems { get; set; } 
} 
+0

genéricos están disponibles a partir de C# 2.0 :) –

+0

Esta es una muy buena forma de implementar esto! – mquander

+0

(arregló la cosa C# 2, espero que no te importe ...) –

0

ICART especifica un getter y setter para CartItems pero su aplicación sólo tiene un encuentro.

4

En su clase abstracta, debe definir que el tipo de devolución de la propiedad CartItems es del tipo List<ICartItem>.

Pero, si realmente quiere que la propiedad es de tipo List<CartItem>, tal vez puede hacer esto:

public interface ICart<TCartItem> where TCartItem : ICartItem 
{ 
    List<TCartItem> CartItems { get; set; } 
} 

public interface ICartItem 
{ 
} 

public abstract class Cart : ICart<CartItem> 
{ 
    public List<CartItem> { get; set; } 
} 

public abstract class CartItem : ICartItem 
{ 
} 
3

Este es un asunto de contra/covarianza.

Se requieren 2 cambios para hacer esta compilación.

1) Elimine la opción "establecer" en la propiedad de la interfaz. (Es sólo la implementación de un encuentro; propiedad, que tiene más sentido, en cualquier caso)

2) Cambio de la compra a:

 
public abstract class Cart : ICart 
{

private List<CartItem> _cartItems = new List<CartItem>(); 

public List<ICartItem> CartItems 
{ ... 

también es muy recomendable cambiar su interfaz para exponer IList en lugar de Lista. Las pautas de diseño (y FxCop) recomiendan no exponer la Lista en la interfaz pública. La lista es un detalle de implementación: IList es la interfaz/tipo de devolución adecuada.

2

Una interfaz es un acuerdo. Un contrato, si lo desea, entre usted y cualquier persona que use su clase. Al decirle a la gente que está implementando la interfaz ICart, les está prometiendo que todos los métodos en la interfaz existen en su clase. Por lo tanto, todos sus métodos deben coincidir con las firmas de los métodos de interfaz.

Para devolver la lista de elementos que implementan ICartItem, necesita utilizar los genéricos como lo sugiere DrJokepu. Esto les dice a todos que la interfaz solo proporciona una lista de objetos que implementan ICartItem, no específicamente ICartItem.

public interface ICart<T> where T : ICartItem 
{ 
    List<T> CartItems { get; set; } 
} 
0

Hay 2 formas de lograr esto. Puede usar genéricos o implementar miembros de interfaz explícitamente.

Genéricos

public interface ICart<TCartItem> where TCartItem : ICartItem 
{ 
    ... 
    List<TCartItem> CartItems { get; set; } 
} 

public interface ICartItem 
{ 
    int ProductId { get; set; } 
    int Quantity { get; set; } 
} 

public abstract class Cart : ICart<CartItem> 
{ 

    private List<CartItem> _cartItems = new List<CartItem>(); 

    public List<CartItem> CartItems 
    { 
     get 
     { 
      return _cartItems; 
     } 
    } 
} 
public abstract class CartItem : ICartItem 
{ 
    ... 
} 

miembros implementados explícitamente

public interface ICart 
{ 
    ... 
    List<ICartItem> CartItems { get; set; } 
} 
public interface ICartItem 
{ 
    int ProductId { get; set; } 
    int Quantity { get; set; } 
} 

public abstract class Cart : ICart 
{ 
    private List<CartItem> _cartItems = new List<CartItem>(); 

    List<ICartItem> ICart.CartItems 
    { 
     get 
     { 
      return CartItems; 
     } 
    } 
    public List<CartItem> CartItems 
    { 
     get 
     { 
      return _cartItems; 
     } 
    } 
} 
public abstract class CartItem : ICartItem 
{ 
    ... 
} 
Cuestiones relacionadas