2009-03-16 37 views
12

Tôi mới tham gia giao diện và lớp trừu tượng. Tôi muốn tạo một vài giao diện để xác định các phương thức và biến cốt lõi cho các đối tượng cho một hệ thống giỏ hàng. Sau đó, tôi muốn tạo ra các lớp trừu tượng mà thực hiện các chức năng cốt lõi. Ý tưởng là chúng có thể được sử dụng bởi các lớp khác theo những cách hơi khác nhau cho các dự án khác nhau.Làm cách nào để xác định loại trả về của một phương thức giao diện là một giao diện khác?

Dưới đây là (cắt xuống) của tôi giao diện:

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

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

Và đây là lớp học của tôi trừu tượng giỏ hàng (một lần nữa, chỉ thấy dòng có liên quan) mà thực hiện ICart:

public abstract class Cart : ICart 
{ 

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

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

Và CartItem của tôi lớp thực hiện ICartItem:

public abstract class CartItem : ICartItem 
{ 
    ... 
} 

Khi tôi cố gắng biên dịch các lớp, tôi gặp lỗi aying: 'Giỏ hàng' không triển khai thành viên giao diện 'CartItems'. 'Cart.CartItems' không thể triển khai 'ICart.CartItems' vì nó không có kiểu trả về phù hợp của System.Collections.Generic.List <ICartItem>. Tôi nghĩ ý tưởng ở đây là giao diện có thể được thực hiện bởi một số lớp thực hiện các chức năng cốt lõi theo nhiều cách khác nhau và thêm các phương thức mới, v.v. Tại sao giao diện của tôi cần biết lớp nào đang được sử dụng , miễn là lớp đó thực sự thực hiện giao diện một cách chính xác?

Trả lời

20

Bạn cần phải Generics sử dụng trong C# 2 để đạt được điều đó:

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

Generics có sẵn như từ C# 2.0 :) –

+0

Đây là một cách khá tốt để thực hiện điều này! – mquander

+0

(cố định điều C# 2; hy vọng bạn không nhớ ...) –

0

ICart định một phương thức getter và setter cho CartItems nhưng việc thực hiện của bạn chỉ có một get.

4

Trong lớp trừu tượng của bạn, bạn nên xác định loại trả về của thuộc tính CartItems, thuộc loại List<ICartItem>.

Nhưng, nếu bạn thực sự muốn rằng bất động sản là loại List<CartItem>, bạn có thể có thể làm điều này:

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

Đây là một vấn đề của Contra/hiệp phương sai.

Cần có 2 thay đổi để thực hiện việc biên dịch này.

1) Xóa tùy chọn "đặt" trên thuộc tính của giao diện. (Nó chỉ thực hiện một get; tài sản, mà làm cho ý nghĩa nhất, trong mọi trường hợp)

2) Thay đổi Giỏ hàng hiện có:

 
public abstract class Cart : ICart 
{

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

public List<ICartItem> CartItems 
{ ... 

Tôi cũng khuyên bạn nên thay đổi giao diện của bạn để lộ IList thay vì Danh sách. Các hướng dẫn thiết kế (và FxCop) khuyên bạn không nên hiển thị Danh sách trong giao diện công khai. Danh sách là chi tiết triển khai - IList là loại giao diện/trả về thích hợp.

2

Giao diện là một thỏa thuận. Một hợp đồng, nếu bạn sẽ, giữa bạn và bất cứ ai sử dụng lớp học của bạn. Bằng cách nói với mọi người rằng bạn đang thực hiện giao diện ICart, bạn hứa với họ rằng tất cả các phương thức trong giao diện tồn tại trên lớp của bạn. Vì vậy, tất cả các phương thức của bạn phải khớp với chữ ký của các phương thức giao diện.

Để trả lại danh sách các mục triển khai ICartItem, bạn cần sử dụng các generics theo đề xuất của DrJokepu. Điều này cho tất cả mọi người biết rằng giao diện chỉ gurentees một danh sách các đối tượng thực hiện ICartItem, không phải ICartItem cụ thể.

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

Có 2 cách để thực hiện việc này. Bạn có thể sử dụng Generics hoặc thực hiện một cách rõ ràng các thành viên giao diện.

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

thành viên thực hiện một cách rõ ràng

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 
{ 
    ... 
} 
Các vấn đề liên quan