是什么使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#只支持interface和委托的协方差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协变地分配s却MyValueTuple不能呢?


2
这可能是编译器的特殊处理方式,就像即使它是一个结构也可以分配nullNullable<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ěŕ靶心!使其可编译,并且按预期方式引发异常
Mong Zhu

Answers:


25

我相信这里实际发生的是一个破坏性任务。元组分配将尝试隐式转换其组件,并且可能分配stringobject,这就是这里发生的情况。

该语言支持具有相同数量元素的元组类型之间的分配,其中每个右侧元素都可以隐式转换为其对应的左侧元素。分配不考虑其他转化。

资源

在sharplab.io上查看


4
我只是在SharpLab上尝试过,肯定可以做到这一点
约翰

3
只是为了强调这一点,在OP的原始示例中,如果更改s类型(string, object)会导致转换错误,这表明项目之间正在进行隐式转换,并且字符串可以隐式转换为字符串,反之则不然。
Eric Lease
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.