Các mã sau đây:"Giao diện không được thực hiện" khi trở về nguồn gốc Loại
public interface ISomeData
{
IEnumerable<string> Data { get; }
}
public class MyData : ISomeData
{
private List<string> m_MyData = new List<string>();
public List<string> Data { get { return m_MyData; } }
}
Tạo các lỗi sau:
error CS0738: 'InheritanceTest.MyData' does not implement interface member 'InheritanceTest.ISomeData.Data'. 'InheritanceTest.MyData.Data' cannot implement 'InheritanceTest.ISomeData.Data' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable'.
Từ một danh sách <T> thực hiện IEnumerable <T>, người ta sẽ nghĩ rằng lớp của tôi sẽ thực hiện giao diện. Ai đó có thể giải thích lý do cơ bản cho việc này không biên dịch?
Như tôi đã có thể nhìn thấy nó, có hai giải pháp khả thi:
- Thay đổi giao diện để cụ thể hơn và đòi hỏi IList được thực hiện.
- Thay đổi lớp học của tôi (MyData) để trả về IEnumerable và triển khai giao diện gốc.
Bây giờ giả sử tôi cũng có đoạn mã sau:
public class ConsumerA
{
static void IterateOverCollection(ISomeData data)
{
foreach (string prop in data.MyData)
{
/*do stuff*/
}
}
}
public class ConsumerB
{
static void RandomAccess(MyData data)
{
data.Data[1] = "this line is invalid if MyPropList return an IEnumerable<string>";
}
}
tôi có thể thay đổi giao diện của tôi để yêu cầu IList được thực hiện (phương án 1), nhưng điều đó hạn chế những người có thể thực hiện các giao diện và số lượng các lớp học có thể được chuyển vào ConsumerA. Hoặc, tôi có thể thay đổi việc thực hiện (lớp MyData) để nó trả về một IEnumerable thay vì một List (tùy chọn 2), nhưng sau đó ConsumerB sẽ phải được viết lại.
Điều này có vẻ là một thiếu sót của C# trừ khi ai đó có thể khai sáng cho tôi.
.. nó không thực sự là một thiếu sót, chỉ là một ví dụ khác của C# chỉ làm những gì bạn nói với nó. VB.NET có rất nhiều tình huống nhỏ như thế này (không chắc chắn về điều này cụ thể mặc dù), nơi họ trình biên dịch sẽ nói "Tôi biết những gì bạn * thực sự * muốn" và sẽ không lỗi bạn thẳng nó ra; C# sẽ nói "Tôi không quan tâm những gì bạn muốn, tất cả những gì tôi biết là những gì bạn đang nói với tôi không bay." – STW
Tôi vẫn không đồng ý và nghĩ rằng đó là một thiếu sót. Giao diện nói "bạn phải cung cấp dữ liệu có thể được liệt kê trên" và lớp của tôi có nội dung "đây là dữ liệu mà bạn có thể liệt kê trên VÀ thực hiện truy cập ngẫu nhiên trên AND v.v.". Tuy nhiên, trình biên dịch nói rằng "bạn không hoàn thành hợp đồng!". – Daniel
@Daniel, nhưng nếu giao diện chỉ chỉ định rằng bạn cung cấp dữ liệu có thể được liệt kê hơn thì nó sẽ không bao giờ cho phép người gọi tận dụng tất cả các tính năng khác. Bằng cách giới hạn bạn phơi bày * chỉ * một đối tượng tương thích với IEnumerable, điều này khiến bạn nhận thấy rằng bất kỳ giá trị gia tăng nào khác của Danh sách ** sẽ không bao giờ có sẵn cho người gọi. Nó làm cho bạn lương tâm về điều đó. Nó giúp bạn không đến đây vào ngày mai và hỏi "MyData.Data cho thấy một Danh sách, nhưng khi một lớp tiêu thụ làm việc với nó, tôi không thể gọi .Thêm()! WTC! C# là stoopid!" –
STW