2009-03-16 18 views
12

Sono nuovo alle interfacce e alle classi astratte. Voglio creare un paio di interfacce per definire i metodi e le variabili fondamentali per gli oggetti per un sistema di carrello della spesa. Quindi voglio creare classi astratte che implementino le funzioni principali. L'idea è che possano essere utilizzati da altre classi in modi leggermente diversi per i diversi progetti.Come definire il tipo di restituzione di un metodo di interfaccia come un'altra interfaccia?

Qui sono le mie (cut-down) interfacce:

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

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

Ed ecco la mia classe astratta Carrello (di nuovo, mostrando solo le linee interessate) che implementa Icart:

public abstract class Cart : ICart 
{ 

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

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

E il mio CartItem classe che implementa ICartItem:

public abstract class CartItem : ICartItem 
{ 
    ... 
} 

Quando provo a compilare le classi ottengo un errore s Aying: 'Carrello' non implementa il membro dell'interfaccia 'CartItems'. 'Cart.CartItems' non può implementare 'ICart.CartItems' perché non ha il tipo di restituzione corrispondente di System.Collections.Generic.List <ICartItem>.

Ho pensato che l'idea qui è che l'interfaccia può essere implementata da un certo numero di classi che eseguono le funzioni principali in modi diversi e aggiungono nuovi metodi, ecc. Perché la mia interfaccia deve sapere quale classe viene effettivamente utilizzata , purché quella classe implementa correttamente l'interfaccia?

risposta

20

È necessario farmaci generici utente in C# 2 per raggiungere questo:

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

farmaci generici sono disponibili come da C# 2.0 :) –

+0

Questo è un buon modo per implementare questo! – mquander

+0

(corretta la cosa C# 2, spero non ti dispiaccia ...) –

0

ICART specifica un getter e setter per CartItems ma l'implementazione ha solo un get.

4

Nella classe astratta, è necessario definire che il tipo di restituzione della proprietà CartItems sia di tipo List<ICartItem>.

Ma, se si vuole veramente che la proprietà è di tipo List<CartItem>, si può forse fare questo:

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

Questa è una questione di contra/covarianza.

Sono necessarie 2 modifiche per eseguire questa compilazione.

1) Rimuovere l'opzione "set" sulla proprietà dell'interfaccia. (E 'solo l'attuazione di un get, la proprietà, il che rende più senso, in ogni caso)

2) Modifica carrello:

 
public abstract class Cart : ICart 
{

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

public List<ICartItem> CartItems 
{ ... 

Ho anche consigliare vivamente cambiare l'interfaccia per esporre IList invece di Elenco. Le linee guida di progettazione (e FxCop) raccomandano di non esporre Elenco nell'interfaccia pubblica. List è un dettaglio di implementazione - IList è l'interfaccia appropriata/tipo di ritorno.

2

Un'interfaccia è un accordo. Un contratto, se vuoi, tra te e chiunque usi la tua classe. Dicendo alla gente che stai implementando l'interfaccia ICart, prometti loro che nella tua classe esistono tutti i metodi nell'interfaccia. Pertanto, tutti i metodi devono corrispondere alle firme dei metodi dell'interfaccia.

Per restituire l'elenco degli articoli che implementano ICartItem, è necessario utilizzare i generici come suggerito da DrJokepu. Questo dice a tutti che l'interfaccia fornisce solo un elenco di oggetti che implementano ICartItem, non in particolare ICartItem.

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

Ci sono 2 modi per farlo. Puoi utilizzare i generici o implementare esplicitamente i membri dell'interfaccia.

Generics

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 
{ 
    ... 
} 

membri in modo esplicito attuate

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 
{ 
    ... 
} 
Problemi correlati