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

では、ValueTuplesを共変的に割り当てるMyValueTupleことができるのに、それができないのはなぜですか?


2
これはちょうどあなたが割り当てることができるかのようなコンパイラによる可能性が高い特殊な治療、であるnullNullable<T>それは構造体だにもかかわらず。
juharr

2
実際には第二の割り当てについては、このような、逆コンパイルコードのルックス:ValueTuple<object, string> o = new ValueTuple<object, string>(s.Item1, s.Item2);
ラッセV. Karlsenの

2
タプルは奇妙で、基礎となるCLR表現に依存するのではなく、c#コンパイラのフロントエンドに完全に実装されています。その代入演算子はあなたが思っていることをしていません。
ジェレミーレイクマン

2
暗黙の演算子を追加してpublic static implicit operator MyValueTuple<A, B>(MyValueTuple<string, string> v) { throw new NotImplementedException(); }、割り当てを分解します。ちなみに、いい質問ですね!
Çöđěxěŕ

1
@Çöđěxěŕブルズアイ!これによりコンパイル可能になり、例外が期待どおりにスローされます
Mong Zhu

回答:


25

ここで実際に起こっていることは、破壊的な任務だと思います。タプルの割り当ては、暗黙的にそのコンポーネントを変換しようとします、そして割り当てることが可能であるとstringobject、それはここでは何が起こるかです。

この言語は、同じ数の要素を持つタプル型間の割り当てをサポートしています。各右側の要素は、対応する左側の要素に暗黙的に変換できます。その他の変換は割り当てでは考慮されません。

ソース

sharplab.ioでそれを見てください


4
私はSharpLabで試してみただけですが、それはまさにそれで十分です
John

3
それを補強するために、OPの元の例では、sタイプを変更する(string, object)と変換エラーが発生し、アイテム間で暗黙的な変換が行われ、文字列は暗黙的に文字列に変換できますが、その逆はできません。
Eric Lease
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.