【问题标题】:C#7 value tuple/deconstruction asymmetryC#7 值元组/解构不对称
【发布时间】:2017-10-10 18:17:38
【问题描述】:

Fiddle here.

给定一个函数(string a, string b) F(),你可以解构它返回的元组:

var (a, b) = F();

(string c, string d) = F();

或者你可以分配它:

var (a, b) e = F();

(string a, string b) f = F();

var g = F();  //  One of these things is not like the others.

类解构器的行为类似于第一种情况。给定一个类CDeconstructor(out string a, out string b)

var c = new C();

var (h, i) = c;

(string j, string k) = c;

但编译器不会使用解构器将其隐式转换为元组:

//  Cannot implicitly convert type 'C' to '(string a, string b)'
var (a, b) l = c;

显然你可以机械地写一个基于解构器的隐式转换:

public static implicit operator (string a, string b) (C c)
{
    c.Deconstruct(out string a, out string b);
    return (a, b);
}

尽管解构和赋值情况在语法上看起来相似,但将引用分配给元组与将类解构为变量然后将它们放入新的元组中是不同的。但是,您可以将(int x, int y) 隐式转换为(double x, double y)。值元组是一种语法糖特性,它做它看起来做的事情,更不用说实现细节了。

如果我想到这一点,C# 团队也想到了,如果他们选择不为隐式转换添加“魔法”支持,他们有充分的理由1

自动进行隐式转换是个坏主意,有什么积极的理由吗?

或者它是那些被认为价值不足以证明成本合理的功能之一?


这是来自that fiddle的代码:

public class Program
{
    public static void Main()
    {
        (string a, string b) = F();

        (string a, string b) ab = F();

        Console.WriteLine($"a: {a} b: {b} ab: {ab}");


        var c = new C();

        (string d, string e) = c;

        //  Cannot implicitly convert type 'C' to '(string a, string b)'
        (string a, string b) f = c;

        Console.WriteLine($"d: {d} e: {e} f: {f}");

        //  Covariance
        (object c, object d) g = F();
        //  Implicit conversion
        (double x, double y) t = G();
    }

    public static (string a, string b) F() 
        => ("A", "B");

    public static (int x, int y) G() 
        => (0, 1);
}

public class C
{
    public String A = "A";
    public String B = "B";

    public void Deconstruct(out String a, out String b)
    {
        a = A;
        b = B;
    }
}

1 C# 团队可能并不比所有人都聪明,但我从来没有因为赌他们至少和我一样聪明而赔过钱。

【问题讨论】:

  • 显然,您不希望隐式解构,就像您通常不希望从一个类隐式转换到另一个类一样。此外,从同一来源同时使用元组和解构变量也没有多大意义。它只会使代码更难理解。作为一名语言设计者,无论如何开始更严格然后最终泛化而不是相反是有意义的。例如,引用类型默认可以为空的事实是 C# 现在被认为是最大的设计错误之一......

标签: c# c#-7.0 valuetuple


【解决方案1】:

(string a, string b) ab 声明了一个名为ab 的元组类型(string a, string b)single 变量。这使您可以编写 ab.aab.b,但不能编写 ab

(string a, string b) f = c; 尝试将一个不相关的C 类型转换为此元组类型。除非你写一个演员表,否则这是不可能发生的。

具体来说,顾名思义,解构只允许你分配给变量;它不允许您转换为不相关的类型。

【讨论】:

    【解决方案2】:

    在 C# 7 发布之前,让解构行为像隐式转换器一样的能力是(我的要求,所以我在这里有偏见)。团队的回应是(正如我读到的那样),它被要求太接近 C# 7 版本并且实施起来需要很长时间,所以不考虑。由于这将是一个突破性的变化,它永远不会发生。

    有关此事的实际讨论,请参阅“Allow Deconstruct and implicit operator to both support deconstruction and conversion to tuple types”roslyn repo issue。

    【讨论】:

      【解决方案3】:

      这是实现您想要做的事情的一种方法:在您的代码示例中,使用(string a, string b) f = (_, _) = c; 而不是(string a, string b) f = (_, _) = c;

      您还可以编写一个用户定义的从您的类型到您需要的元组类型的转换。

      【讨论】:

      • 我真的很佩服这里的把戏!我永远不想在生产代码中看到它,但它很整洁:)
      猜你喜欢
      • 2017-12-12
      • 2018-03-06
      • 1970-01-01
      • 2017-10-06
      • 2017-04-15
      • 1970-01-01
      • 2018-10-04
      • 2017-05-26
      相关资源
      最近更新 更多