2015-12-11 19 views
9

Trong đoạn code mẫu dưới đây, tại sao các cuộc gọi đến ArrayMethod thất bại cho một loại genric khi tôi không bao gồm các hạn chế classĐi qua một mảng

public interface IFoo { } 
public interface IBar : IFoo { } 

public class Test 
{ 
    public void ClassConstraintTest<T>() where T : class, IFoo 
    { 
     T[] variable = new T[0]; 
     ArrayMethod(variable); 
    } 

    public void GenericTest<T>() where T : IFoo 
    { 
     T[] variable = new T[0]; 
     ArrayMethod(variable); // Compilation error: Can't convert T[] to IFoo[] 
    } 

    public void InheritanceTest() 
    { 
     IBar[] variable = new IBar[0]; 
     ArrayMethod(variable); 
    } 

    public void ArrayMethod(IFoo[] args) { } 
} 

Trả lời

9

Nó vì array covariance, ví dụ, thực tế là MySubtype[] là một loại phụ của MyType[], chỉ hoạt động cho các loại tham chiếu. Ràng buộc class đảm bảo rằng T là loại tham chiếu.

(Lưu ý rằng, khi nhìn lại, mảng hiệp phương sai là considered to be a bad idea Cố gắng tránh nó nếu bạn có thể, ví dụ, bằng cách làm cho ArrayMethod generic hoặc bằng cách sử dụng IEnumerable<IFoo> để thay thế..)

+0

Một hệ thống kiểu tốt nên có loại so khớp có thể được sử dụng làm mảng có các mục có thể được đọc, hoán đổi hoặc sao chép trong mảng. Các loại mảng trong .NET và Java có thể được sử dụng một cách an toàn theo kiểu biến đổi như các kiểu như vậy và có thể được sử dụng một cách an toàn theo kiểu không biến đổi như các bộ sưu tập có thể ghi tự do. Có lẽ sẽ tốt hơn nếu có nhiều loại tham chiếu đến mảng, với những khả năng được quảng cáo khác nhau, nhưng IMHO những người chỉ đơn giản nói các mảng biến đổi là một "sai lầm" đã không thực sự tìm ra chi phí của các giải pháp thay thế. – supercat

5

Nói tóm lại: mảng hiệp phương sai chỉ hoạt động khi cả hai mảng đều thuộc loại tham chiếu (class).

Để hiểu điều này, bạn phải hiểu bố cục bộ nhớ của các loại mảng khác nhau. Trong C# chúng ta có mảng giá trị (int[], float[], DateTime[], bất kỳ người dùng định nghĩa struct[]) trong đó mỗi điều được lưu trữ liên tục bên trong mảng, và tham khảo các mảng (object[], string[], bất kỳ người dùng định nghĩa class[], interface[], hoặc delegate[]), nơi tài liệu tham khảo được lưu trữ tuần tự bên trong mảng và các đối tượng được lưu trữ bên ngoài mảng bất cứ nơi nào chúng phù hợp với bộ nhớ.

Khi bạn yêu cầu mà công việc phương pháp trên bất kỳ T (không có : class hạn chế), bạn cho phép một trong hai loại mảng, nhưng trình biên dịch biết một thực tế là bất kỳ int[] (hoặc bất kỳ mảng giá trị khác) không phải là bằng cách nào đó kỳ diệu trở thành IFoo[] hợp lệ (hoặc bất kỳ mảng tham chiếu nào khác) và cấm chuyển đổi. Điều này xảy ra ngay cả khi cấu trúc của bạn triển khai IFoo vì không có lý do nào khác hơn IFoo[] là một mảng tham chiếu và một T[] sẽ là một mảng giá trị.

Tuy nhiên, khi bạn xác định rằng T là một loại tài liệu tham khảo (ví dụ: khai báo class), bây giờ có thể rằng T[] là một giá trị IFoo[] vì họ đều là những mảng tham khảo. Vì vậy, trình biên dịch cho phép mã sử dụng các quy tắc hiệp phương sai (mà bạn có thể sử dụng T[] trong đó IFoo[] là bắt buộc vì T là một loại phụ của IFoo).

Các vấn đề liên quan