2009-03-16 15 views
12

Jestem nowy w interfejsach i klasach abstrakcyjnych. Chcę utworzyć kilka interfejsów do definiowania podstawowych metod i zmiennych dla obiektów dla systemu koszyka na zakupy. Następnie chcę utworzyć klasy abstrakcyjne, które implementują podstawowe funkcje. Chodzi o to, że mogą być używane przez inne klasy w nieco inny sposób dla różnych projektów.Jak zdefiniować typ powrotu dla metody interfejsu jako innego interfejsu?

Oto moje (cut-dół) Interfejsy:

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

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

A oto moja klasa abstrakcyjna Koszyk (ponownie, tylko pokazywanie odpowiednich linii), która implementuje Icart:

public abstract class Cart : ICart 
{ 

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

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

i mój CartItem klasa implementująca ICartItem:

public abstract class CartItem : ICartItem 
{ 
    ... 
} 

Kiedy próbuję skompilować klasy, pojawia się błąd s aying: "Koszyk" nie implementuje członka interfejsu "CartItems". "Cart.CartItems" nie może zaimplementować "ICart.CartItems", ponieważ nie ma zgodnego typu zwrotu System.Collections.Generic.List <ICartItem>.

Pomyślałem, że pomysł jest taki, że interfejs może być implementowany przez wiele klas, które wykonują podstawowe funkcje na różne sposoby i dodają nowe metody, itp. Dlaczego mój interfejs musiałby wiedzieć, która klasa jest faktycznie używana , tak długo jak ta klasa poprawnie implementuje interfejs?

Odpowiedz

20

Trzeba generycznych użytkownika w języku C# 2, aby to osiągnąć:

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

generyczne są dostępne od C# 2.0 :) –

+0

To bardzo dobry sposób, aby wdrożyć to! – mquander

+0

(poprawiono C# 2, mam nadzieję, że nie masz nic przeciwko ...) –

0

Icart określa getter i setter dla CartItems ale implementacja ma tylko dostać.

4

W swojej klasie abstrakcyjnej należy zdefiniować, że typ zwracany przez właściwość CartItems ma typ List<ICartItem>.

Ale jeśli naprawdę chcesz, że nieruchomość jest typu List<CartItem>, można być może to zrobić:

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

Jest to kwestia contra/kowariancji.

Do tej kompilacji potrzebne są 2 zmiany.

1) Usuń opcję "ustaw" z właściwości interfejsu. (To wdrażaniu tylko get; właściwość, która sprawia, że ​​największy sens, w każdym razie)

2) Zmiana Koszyk do:

 
public abstract class Cart : ICart 
{

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

public List<ICartItem> CartItems 
{ ... 

Ja również bardzo polecam zmianę interfejsu narazić IList zamiast Lista. Zalecenia projektowe (i FxCop) nie zalecają wystawiania Listy w interfejsie publicznym. Lista jest szczegółem implementacji - IList jest odpowiednim interfejsem/typem powrotu.

2

Interfejs to umowa. Umowa, jeśli wolisz, między tobą a każdym, kto korzysta z twojej klasy. Mówiąc ludziom, że implementujesz interfejs ICart, obiecujesz im, że wszystkie metody w interfejsie istnieją w twojej klasie. Zatem wszystkie twoje metody muszą być zgodne z sygnaturami metod interfejsu.

Aby zwrócić listę pozycji, które implementują ICartItem, należy użyć generycznych zgodnie z sugestią DrJokepu. To mówi wszystkim, że interfejs tylko wyświetla listę obiektów implementujących ICartItem, a nie tylko ICartItem.

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

Istnieją 2 sposoby na osiągnięcie tego. Możesz użyć generycznych lub jawnie zaimplementować elementy interfejsu.

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

Jawnie realizowane członkowie

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 
{ 
    ... 
} 
Powiązane problemy