Câu trả lời cho những câu hỏi như sau: List <T> hoặc IList <T> dường như luôn đồng ý rằng trả về một giao diện tốt hơn là trả về một triển khai cụ thể của một tập hợp. Nhưng tôi đang đấu tranh với điều này. Việc khởi tạo một giao diện là không thể, vì vậy nếu phương thức của bạn đang trả về một giao diện, thì nó thực sự vẫn trả về một triển khai cụ thể. Tôi đã thử nghiệm một chút với điều này bằng cách viết 2 phương pháp nhỏ:
public static IList<int> ExposeArrayIList()
{
return new[] { 1, 2, 3 };
}
public static IList<int> ExposeListIList()
{
return new List<int> { 1, 2, 3 };
}
Và sử dụng chúng trong chương trình thử nghiệm của tôi:
static void Main(string[] args)
{
IList<int> arrayIList = ExposeArrayIList();
IList<int> listIList = ExposeListIList();
//Will give a runtime error
arrayIList.Add(10);
//Runs perfectly
listIList.Add(10);
}
Trong cả hai trường hợp khi tôi cố gắng thêm một giá trị mới, trình biên dịch của tôi không cho tôi lỗi nào, nhưng rõ ràng là phương thức hiển thị mảng của tôi dưới dạng một IList<T>
lỗi thời gian chạy khi tôi cố gắng thêm thứ gì đó vào nó. Vì vậy, những người không biết điều gì đang xảy ra trong phương thức của tôi và phải thêm các giá trị vào nó, trước tiên buộc phải sao chép của tôi IList
vào a List
để có thể thêm các giá trị mà không có nguy cơ mắc lỗi. Tất nhiên, họ có thể đánh máy để xem liệu họ đang xử lý a List
hay an Array
, nhưng nếu họ không làm như vậy và họ muốn thêm các mục vào bộ sưu tập, họ không có lựa chọn nào khác là sao chép IList
vào a List
, ngay cả khi nó đã là mộtList
. Một mảng không bao giờ nên được hiển thị như IList
?
Một mối quan tâm khác của tôi dựa trên câu trả lời được chấp nhận của câu hỏi được liên kết (tôi nhấn mạnh):
Nếu bạn đang hiển thị lớp của mình thông qua một thư viện mà những người khác sẽ sử dụng, bạn thường muốn hiển thị nó qua các giao diện hơn là triển khai cụ thể. Điều này sẽ hữu ích nếu bạn quyết định thay đổi việc triển khai lớp của mình sau này để sử dụng một lớp cụ thể khác. Trong trường hợp đó, người dùng thư viện của bạn sẽ không cần cập nhật mã của họ vì giao diện không thay đổi.
Nếu bạn chỉ đang sử dụng nó trong nội bộ, bạn có thể không quan tâm lắm, và sử dụng List có thể ok.
Hãy tưởng tượng ai đó thực sự đã sử dụng phương pháp của tôi IList<T>
mà họ nhận được từ ExposeListIlist()
phương pháp của tôi giống như vậy để thêm / bớt các giá trị. Mọi thứ đều hoạt động tốt. Nhưng bây giờ giống như câu trả lời gợi ý, bởi vì trả về một giao diện linh hoạt hơn, tôi trả về một mảng thay vì Danh sách (không có vấn đề gì với tôi!), Sau đó chúng sẽ được xử lý ...
TLDR:
1) Để lộ một giao diện gây ra các phôi không cần thiết? Điều đó không thành vấn đề?
2) Đôi khi nếu người dùng của thư viện không sử dụng truyền, mã của họ có thể bị hỏng khi bạn thay đổi phương thức của mình, mặc dù phương thức vẫn hoàn toàn tốt.
Tôi có lẽ đã suy nghĩ quá nhiều về điều này, nhưng tôi không nhận được sự đồng thuận chung rằng việc trả lại giao diện được ưu tiên hơn là trả lại một triển khai.
IEnumerable<T>
và bạn có thời gian biên dịch an toàn. Bạn vẫn có thể sử dụng tất cả các phương thức mở rộng LINQ thường cố gắng tối ưu hóa hiệu suất bằng cách truyền nó đến một loại cụ thể (ThíchICollection<T>
sử dụng thuộcCount
tính thay vì liệt kê nó).