Що робить ValueTuple коваріантом?


35

Це складено правильно у C # 7.3 (Рамка 4.8):

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

Я знаю, що це синтаксичний цукор для наступного, який також складено правильно:

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

Отже, виявляється, що ValueTuples можна призначати коваріантно , що приголомшливо !

На жаль, я не розумію, чому : у мене було враження, що C # підтримує лише коваріацію на інтерфейсах та делегатах . ValueTypeце не те.

Насправді, коли я намагаюся дублювати цю функцію з власним кодом, я не можу:

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>'

Отже, чому можна ValueTupleпризначати коваріантно, а MyValueTupleне можна?


2
Ймовірно, це спеціальне звернення компілятора, як і те, як ви можете призначити nullйого, Nullable<T>навіть якщо це структура.
juharr

2
Власне, декомпільований код виглядає таким чином для другого завдання:ValueTuple<object, string> o = new ValueTuple<object, string>(s.Item1, s.Item2);
Lasse V. Karlsen

2
Кортежі дивні і реалізовані повністю в передньому кінці компілятора c #, замість того, щоб покладатися на базове представлення CLR. Цей оператор призначення не робить те, що ви думаєте.
Джеремі

2
Додайте неявний оператор, який public static implicit operator MyValueTuple<A, B>(MyValueTuple<string, string> v) { throw new NotImplementedException(); }деконструює призначення. Крім того, велике питання до речі!
Çöđěxěŕ

1
@ Çöđěxěŕ бики очей! це робить його складним, і виняток
Монг Чжу

Відповіді:


25

Я вважаю, що насправді тут відбувається завдання руйнування. Призначення Кортеж буде намагатися неявно перетворити його компоненти, і як можна призначити stringна object, це те , що тут відбувається.

Мова підтримує призначення між типами кортежів, які мають однакову кількість елементів, де кожен правий елемент може бути неявно перетворений у відповідний лівий бічний елемент. Інші конверсії не враховуються для призначень.

Джерело

Дивіться це на sharplab.io


4
Я просто спробував це на SharpLab і досить впевнений, що він робить саме це .
Іван

3
Просто щоб підкріпити це, в оригінальному прикладі OP, якщо ви зміните sтип, (string, object)це призводить до помилки перетворення, що вказує на те, що між елементами відбувається неявна конверсія, а рядок може бути неявно перетворений у рядок, але не навпаки.
Ерік Оренда
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.