2013-04-26 40 views
9

Exact rules for variance validity có chút mơ hồ và không cụ thể. Tôi sẽ liệt kê các quy tắc cho những gì làm cho một loại hợp lệ-covariantly, và đính kèm một số truy vấn và chú thích cá nhân cho mỗi quy tắc.Các quy tắc khác nhau trong C#

Một loại là hợp lệ covariantly nếu nó là:

1) một loại con trỏ, hoặc một loại phi generic.

Các điểm và loại không chung chung không phải là biến thể trong C#, ngoại trừ các mảng và đại biểu không chung chung. Các lớp chung, cấu trúc và enums là bất biến. Tôi có ở đây không?

2) Một loại mảng T [] trong đó T có giá trị covariantly.

Vì vậy, điều này có nghĩa rằng nếu loại yếu tố T của một mảng T[] là hiệp biến (tham chiếu hoặc mảng kiểu phần tử), sau đó mảng là hiệp biến, và nếu các loại nguyên tố là bất biến (kiểu giá trị), sau đó Array loại là bất biến. Mảng không thể là contravariant trong C#. Tôi có ở đây không?

3) Kiểu tham số kiểu chung, nếu nó không được khai báo là trùng lặp.

Chúng tôi thường nói rằng một loại chung là biến thể trên một loại thông số, nhưng đối với loại thông số là biến thể trên riêng nó. Đây có phải là một hình thức ngắn để nói điều đó không? ví dụ, loại chung T<out D> là biến thể trên D (do đó covariantly hợp lệ), do đó chúng ta có thể nói rằng tham số kiểu D là covariantly hợp lệ. Tôi có đúng không?

4) Lớp xây dựng, cấu trúc, enum, giao diện hoặc loại đại biểu X có thể có giá trị covariantly. Để xác định nếu nó là, chúng tôi kiểm tra từng loại đối số khác nhau, tùy thuộc vào việc các tham số kiểu tương ứng đã được khai báo là covariant (out), contravariant (in), hoặc bất biến (không). (Tất nhiên các tham số kiểu chung của các lớp và cấu trúc sẽ không bao giờ được khai báo 'out' hoặc 'in'; chúng sẽ luôn luôn là bất biến.) Nếu tham số kiểu thứ i được khai báo là covariant, thì Ti phải hợp lệ covariantly. Nếu nó được khai báo là contravariant, thì Ti phải có giá trị tương ứng. Nếu nó được khai báo là bất biến, thì Ti phải có giá trị bất biến.

Quy tắc cuối cùng này, từ trên xuống dưới, hoàn toàn không rõ ràng.

Có phải chúng ta đang nói về phương sai của loại chung trên tất cả các tham số loại vào/ra/bất biến của nó không? Theo định nghĩa, một kiểu generic có thể là covariant/contravariant/invariant trên một loại paramter tại một thời điểm. Để được biến đổi hoặc bất biến, trong trường hợp này, trên tất cả các tham số kiểu của nó cùng một lúc không giữ bất kỳ ý nghĩa nào. Điều đó có nghĩa là gì?

Tiến lên. Để xác định xem kiểu generic có hợp lệ hay không, chúng ta kiểm tra các đối số kiểu của nó (không phải kiểu paramters). Vì vậy, nếu tham số kiểu tương ứng là covariant/contravariant/invariant, thì đối số kiểu là covariantly/contravariantly/invariantly hợp lệ tương ứng ...

Tôi cần quy tắc này được giải thích chi tiết hơn.


Chỉnh sửa: Cảm ơn Eric. Được đánh giá cao!

Tôi hoàn toàn hiểu ý nghĩa của giá trị covariantly/contravariantly/invariantly hợp lệ. Một loại là hợp lệ covriantly, nếu nó chắc chắn không contravariant, có nghĩa là nó có thể là bất biến. hoàn toàn ổn!

Đối với quy tắc thứ 4, bạn làm theo quy trình làm thế nào để xác định xem loại chung được xây dựng có hợp lệ đúng hay không, như được xác định trong quy tắc. Nhưng, làm thế nào để bạn xác định xem một đối số kiểu được khai báo là covariant (out) có hợp lệ không?

Ví dụ, trong giao diện được xây dựng khép kín Tôi {} của giao diện chung tôi {...}, nên không phải là thực tế rất rằng kiểu tranh luận object được khai báo là một loại hiệp biến tham số (out U) trong khai báo giao diện chung có nghĩa là đối số đối số kiểu là covariant? Tôi nghĩ rằng nó nên. Cuz đó chính là định nghĩa của sự biến đổi.

Ngoài ra, các quy tắc thứ hai:

2) Một loại mảng T [] trong đó T là hợp lệ covariantly.

mảng yếu tố loại T là hợp lệ covariantly nghĩa là gì? Bạn có nghĩa là loại phần tử là một loại giá trị (bất biến trong trường hợp này) hoặc loại tham chiếu (biến thể trong trường hợp này)?

Cuz phép chiếu TT[] chỉ là biến thể nếu T là loại tham chiếu.

+0

Thử lại? :) – Gjeltema

+0

Nó thực sự không giống như Eric Lippert là mơ hồ hoặc mơ hồ. Tôi cho một người sẽ chờ anh ta cân nhắc trước khi kiểm tra chiều sâu của vũng nước nhỏ này. –

+0

Bài đăng này là Gjeltema khác nhau. Trong bài trước của tôi về phương sai, sự hiểu biết của tôi về phương sai và các thuật ngữ dạng ngắn liên quan của nó đã được làm rõ. –

Trả lời

12

Bạn nói đúng quy tắc cuối cùng là điều khó hiểu nhất nhưng tôi đảm bảo với bạn rằng nó không rõ ràng.

Một hoặc hai ví dụ sẽ hữu ích.Xem xét khai báo kiểu này:

interface I<in T, out U, V> { ... } 

là loại covariantly hợp lệ?

I<string, object, int> { } 

Hãy xem qua định nghĩa của chúng tôi.

Để xác định xem nó có khác nhau hay không, tùy thuộc vào tham số kiểu tương ứng được khai báo là biến thể

OK, vì vậy đối số loại là string, objectint. Các thông số tương ứng là in T, out UV, tương ứng.

Nếu tham số loại thứ i được khai báo là covariant (out), thì Ti phải hợp lệ covariantly.

Tham số loại thứ hai là out U, vì vậy object phải có giá trị covariantly hợp lệ. Nó là.

Nếu nó được khai báo là contravariant (in), thì Ti phải có giá trị ngược lại.

Lần đầu tiên được khai báo in T, vì vậy string phải có giá trị hợp lý. Nó là.

Nếu nó được khai báo là bất biến thì Ti phải có giá trị bất biến.

Thứ ba V là bất biến, vì vậy int phải là hợp lệ bất biến; nó phải vừa hợp lệ vừa phức tạp và covariantly. Nó là.

Chúng tôi vượt qua cả ba lần kiểm tra; loại I<string, object, int> là hợp lệ covariantly.

OK, điều đó thật dễ dàng.

Bây giờ, hãy xem xét một khó khăn hơn.

interface IEnumerable<out W> { ... } 
interface I<in T, out U, V> 
{ 
    IEnumerable<T> M(); 
} 

IEnumerable<T> bên trong I là một loại. IEnumerable<T> có được sử dụng bên trong I hợp lệ không?

Hãy xem qua định nghĩa của chúng tôi. Chúng tôi có đối số kiểu T tương ứng với thông số loại out W. Lưu ý rằng T là thông số loại của I và loại đối số của IEnumerable.

Nếu tham số loại thứ i (W) đã được khai báo là hiệp biến (out), sau đó Ti (T) phải có giá trị covariantly.

OK, vì vậy cho IEnumerable<T> trong I mới có giá trị covariantly, T phải có giá trị covariantly. Là nó? KHÔNG. T đã được khai báo là in T. Tham số kiểu được khai báo in không bao giờ hợp lệ. Do đó, loại IEnumerable<T> được sử dụng bên trong I không hợp lệ, vì điều kiện "phải" bị vi phạm.

Một lần nữa, như tôi đã nói trong câu trả lời cho câu hỏi trước của bạn, nếu "hợp lệ có giá trị" và "hợp lệ contravariantly" đang cho bạn đau buồn, chỉ cần cung cấp cho họ tên khác nhau. Chúng là những thuộc tính chính thức được xác định rõ; bạn có thể gọi cho họ bất cứ điều gì bạn muốn nếu nó giúp bạn dễ hiểu hơn.

+0

Cảm ơn Eric. Bạn có thể trả lời hai câu hỏi SMALL mới được thêm vào cuối bài đăng gốc của tôi không? –

4

Không, chú thích của bạn bị rối tung lên.

Bài viết đó là thực sự khó hiểu, một phần vì "hợp lệ biến đổi hợp lệ" không có gì để làm với hiệp phương sai. Eric không chỉ ra điều đó, nhưng nó có nghĩa là đối với mỗi câu bạn phải "suy nghĩ" ý nghĩa tự nhiên, sau đó suy nghĩ về các định nghĩa kỳ lạ này cho "covariantly hợp lệ", "contravariantly hợp lệ" và "bất biến hợp lệ".

Tôi đặc biệt khuyên bạn nên đọc về Nguyên tắc thay thế Liskov và sau đó nghĩ về khả năng thay thế. Hiệp phương sai, contravariance, và invariance có định nghĩa rất đơn giản khi nhìn từ quan điểm LSP. Sau đó, bạn có thể nhận thấy rằng các quy tắc C# tại thời gian biên dịch không khớp chính xác với LSP (thật không may - và đây chính là một sai lầm được thực hiện trong Java và sao chép vào C# để giúp các lập trình viên của tòa án Java). Mặt khác, khi chạy các quy tắc LSP, nên nếu bạn bắt đầu với các quy tắc đó, bạn sẽ viết mã mà cả hai biên dịch và chạy chính xác, mà tôi nghĩ là một nỗ lực đáng giá hơn việc học các quy tắc ngôn ngữ C# (trừ khi bạn đang viết trình biên dịch C#).

4

làm cách nào để bạn xác định xem đối số kiểu được khai báo là covariant (out) có hợp lệ không?

đọc quy tắc 3.

trong đóng xây dựng giao diện I{string, object int> của giao diện chung I<in T, out U, V>, không nên chính sự kiện là kiểu lập luận object được khai báo là một tham số kiểu hiệp biến out U trong khai báo giao diện chung có nghĩa là đối số kiểu object là biến thể?

Trước tiên, bạn đang sử dụng "biến thể", nơi bạn có nghĩa là "hợp lệ biến đổi". Hãy nhớ rằng, đây là những điều khác nhau.

Thứ hai, chúng ta hãy xem lại lần nữa. Giá trị object có hợp lệ không? Có, theo quy tắc 1. Có phải I<string, object, int> có giá trị covariantly không? Có, theo quy tắc 3, tuyên bố rằng:

  • Đối số loại tương ứng với T phải có giá trị đáng kể.
  • Đối số loại tương ứng với U phải có giá trị covariantly hợp lệ.
  • Đối số loại tương ứng với V phải là cả hai.

Vì cả ba điều kiện đều được đáp ứng, I<string, object, int> có giá trị covariantly.

Trong "Một loại mảng T [] trong đó T là hợp lệ covariantly" yếu tố mảng loại T có giá trị covariantly có nghĩa là gì?

Tôi không hiểu câu hỏi. Chúng tôi đang xác định ý nghĩa của "giá trị covariantly". Quy tắc 2 là một phần của định nghĩa "covariantly valid".

Ví dụ: object[] có giá trị hợp lệ không? Có, bởi vì object có giá trị covariantly.Nếu chúng tôi có:

interface IFoo<out T> { T[] M(); } 

T[] có giá trị covariantly? Có, bởi vì T có giá trị covariantly.

Nếu chúng ta có

interface IBar<in T> { T[] M(); } 

T[] covariantly hợp lệ? Không. Đối với một loại mảng hợp lệ có thể hợp lệ, loại phần tử của nó phải có giá trị covariantly hợp lệ, nhưng T thì không.

+0

OK! Tôi đã vô thức bối rối các thuật ngữ khác nhau với nhau. Đánh giá cao Eric. –

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