Việc triển khai không thực hiện phương sai triển khai giao diện sẽ phải là biến thể trong kiểu trả về và contravariant trong các loại đối số.
Ví dụ:
public interface IFoo
{
object Flurp(Array array);
}
public class GoodFoo : IFoo
{
public int Flurp(Array array) { ... }
}
public class NiceFoo : IFoo
{
public object Flurp(IEnumerable enumerable) { ... }
}
Cả hai đều là hợp pháp theo quy định "mới", phải không? Nhưng những gì về điều này:
public class QuestionableFoo : IFoo
{
public double Flurp(Array array) { ... }
public object Flurp(IEnumerable enumerable) { ... }
}
Rất khó để biết triển khai ngầm định nào tốt hơn ở đây. Giá trị đầu tiên là đối sánh chính xác cho loại đối số, nhưng không khớp với kiểu trả về. Thứ hai là đối sánh chính xác cho loại trả về, nhưng không phải là loại đối số. Tôi đang nghiêng về phía đầu tiên, bởi vì bất cứ ai sử dụng giao diện IFoo
chỉ có thể cung cấp cho nó một Array
, nhưng nó vẫn không hoàn toàn rõ ràng.
Và đây không phải là điều tồi tệ nhất, cho đến nay. Nếu chúng tôi làm điều này thay thế:
public class EvilFoo : IFoo
{
public object Flurp(ICollection collection) { ... }
public object Flurp(ICloneable cloneable) { ... }
}
Giải thưởng nào giành giải thưởng? Đó là một tình trạng quá tải hợp lệ hoàn toàn, nhưng ICollection
và ICloneable
không có gì để làm với nhau và Array
thực hiện cả hai. Tôi không thể nhìn thấy một giải pháp rõ ràng ở đây.
Nó chỉ trở nên tồi tệ hơn nếu chúng ta bắt đầu thêm quá tải vào giao diện chính nó:
public interface ISuck
{
Stream Munge(ArrayList list);
Stream Munge(Hashtable ht);
string Munge(NameValueCollection nvc);
object Munge(IEnumerable enumerable);
}
public class HateHateHate : ISuck
{
public FileStream Munge(ICollection collection);
public NetworkStream Munge(IEnumerable enumerable);
public MemoryStream Munge(Hashtable ht);
public Stream Munge(ICloneable cloneable);
public object Munge(object o);
public Stream Munge(IDictionary dic);
}
Chúc may mắn cố gắng để làm sáng tỏ bí ẩn này mà không đi điên.
Tất nhiên, tất cả điều này là tranh luận nếu bạn khẳng định rằng việc triển khai giao diện chỉ nên hỗ trợ phương sai kiểu trả về và không phải phương sai kiểu đối số. Nhưng hầu như tất cả mọi người sẽ xem xét việc thực hiện một nửa như vậy là hoàn toàn bị hỏng và bắt đầu gửi báo cáo lỗi spam, vì vậy tôi không nghĩ rằng nhóm C# sẽ làm điều đó.
Tôi không biết đây có phải là lý do chính thức tại sao nó không được hỗ trợ trong C# ngày hôm nay hay không, nhưng nó sẽ là một ví dụ tốt về loại mã "chỉ ghi" mà nó có thể dẫn đến, và một phần triết lý thiết kế của đội ngũ C# là cố gắng ngăn chặn các nhà phát triển viết mã khủng khiếp.
Nếu giao diện 'IClonable' được viết trước mã của bạn, phương thức Clone có thể trả về các loại cụ thể như thế nào? Người bảo đảm duy nhất chúng tôi có là bất cứ điều gì được trả lại bởi việc bạn thực hiện Clone, sẽ được bắt nguồn từ "Object". Vì bạn phải tuân theo định nghĩa giao diện chính xác, bạn sẽ phải trả lại giao diện được nói là "Đối tượng". –
Ở đây tôi muốn rằng việc thực hiện phương pháp Clone của tôi sẽ có thể trả về kiểu cụ thể không phải là phương thức Clone() của IClonable khi tôi nhúng vào giao diện IClonable. Nhưng điều này là không được phép, chúng tôi nhận được một lỗi biên dịch. Vì vậy, tôi muốn biết lý do, tại sao khái niệm hiệp phương sai hoặc Contravariance không được phép thực hiện một giao diện. – Amit