Điều gì làm cho ValueTuple covariant?


35

Điều này biên dịch chính xác trong C # 7.3 (Khung 4.8):

(string, string) s = ("a", "b");
(object, string) o = s;

Tôi biết rằng đây là đường cú pháp cho những điều sau đây, cũng được biên dịch chính xác:

ValueTuple<string, string> s = new ValueTuple<string, string>("a", "b");
ValueTuple<object, string> o = s;

Vì vậy, có vẻ như ValueTuples có thể được gán covariantly , thật tuyệt vời !

Thật không may, tôi không hiểu tại sao : Tôi có ấn tượng rằng C # chỉ hỗ trợ hiệp phương sai trên các giao diện và đại biểu . ValueTypekhông phải là.

Thực tế, khi tôi cố gắng sao chép tính năng này bằng mã của riêng mình, tôi đã thất bại:

struct MyValueTuple<A, B>
{
    public A Item1;
    public B Item2;

    public MyValueTuple(A item1, B item2)
    {
        Item1 = item1;
        Item2 = item2;
    }
}

...

MyValueTuple<string, string> s = new MyValueTuple<string, string>("a", "b");
MyValueTuple<object, string> o = s;
// ^ Cannot implicitly convert type 'MyValueTuple<string, string>' to 'MyValueTuple<object, string>'

Vì vậy, tại sao ValueTuples có thể được gán covariantly, nhưng MyValueTuples không thể?


2
Đây có thể là trình xử lý đặc biệt của trình biên dịch, giống như cách bạn có thể gán nullcho Nullable<T>mặc dù đó là một cấu trúc.
juharr

2
Trên thực tế, mã dịch ngược trông như thế này cho nhiệm vụ thứ hai:ValueTuple<object, string> o = new ValueTuple<object, string>(s.Item1, s.Item2);
Lasse V. Karlsen

2
Tuples là lạ và được thực hiện hoàn toàn trong giao diện trình biên dịch c #, thay vì dựa vào một đại diện CLR cơ bản. Toán tử gán đó không làm những gì bạn nghĩ.
Jeremy Lakeman

2
Thêm một toán tử ngầm định public static implicit operator MyValueTuple<A, B>(MyValueTuple<string, string> v) { throw new NotImplementedException(); }nó giải cấu trúc bài tập. Ngoài ra, câu hỏi tuyệt vời bằng cách này!
Çöđěxěŕ

1
@ Çöđěxěŕ mắt bò! điều đó làm cho nó có thể biên dịch được và ngoại lệ được đưa ra như mong đợi
Mong Zhu

Câu trả lời:


25

Tôi tin rằng những gì đang thực sự xảy ra ở đây là một nhiệm vụ hủy diệt. Việc gán Tuple sẽ cố gắng chuyển đổi hoàn toàn các thành phần của nó và như có thể gán stringcho object, đó là những gì xảy ra ở đây.

Ngôn ngữ hỗ trợ gán giữa các loại tuple có cùng số phần tử, trong đó mỗi phần tử bên phải có thể được chuyển đổi hoàn toàn thành phần tử bên trái tương ứng. Các chuyển đổi khác không được xem xét cho các bài tập.

Nguồn

Xem nó trên sharplab.io


4
Tôi mới thử nó trên SharpLab và chắc chắn rằng nó thực hiện chính xác điều đó .
Giăng

3
Chỉ để củng cố rằng, trong ví dụ ban đầu của OP, nếu bạn thay đổi sđể nhập (string, object)nó sẽ dẫn đến lỗi chuyển đổi, chỉ ra rằng chuyển đổi ngầm đang diễn ra giữa các mục và chuỗi có thể được chuyển đổi hoàn toàn thành chuỗi, nhưng ngược lại.
Eric thuê
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.