无法将可解构类型隐式转换为元组

Cannot implicitly convert deconstructable type to Tuple

我有两个使用 Deconstruct() 方法的结构(Point 和 Size)。两者都是 return (int, int) 元组。

我试图在 switch 中将它们解构为 (int, int) 元组变量,但没有成功。编译器给我错误:

Cannot implicitly convert type 'Size' to '(int, int)'.

如何将这两个结构解构为一个元组,以便能够在第二个 switch 表达式中使用它?

using System;

class Program
{
    static string DescribeSize<TDeconstructable>(TDeconstructable deconstructableStruct)
    where TDeconstructable : struct
    {
        (int, int) xy;
        switch (deconstructableStruct)
        {
            case Size size:
                xy = size; //CS0029 error: Cannot implicitly convert type 'Size' to '(int, int)'
                break;
            case Point point:
                xy = point; //CS0029 error: Cannot implicitly convert type 'Point' to '(int, int)'
                break;
            default:
                xy = (0, 0);
                break;
        }

        return xy switch
        {
            (0, 0) => "Empty",
            (0, _) => "Extremely narrow",
            (_, 0) => "Extremely wide",
            _ => "Normal"
        };
    }

    static void Main(string[] args)
    {
        var size = new Size(4, 0);
        var point = new Point(0, 7);
        Console.WriteLine(DescribeSize(size));
        Console.WriteLine(DescribeSize(point));
    }
}

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public void Deconstruct(out int x, out int y)
    {
        x = X;
        y = Y;
    }
}

public readonly struct Size
{
    public int W { get; }
    public int H { get; }

    public Size(int w, int h)
    {
        W = w;
        H = h;
    }

    public void Deconstruct(out int w, out int h)
    {
        w = W;
        h = H;
    }
}

如果需要,您可以将此辅助方法添加到结构中 return ValueTuple。

public ValueTuple<int, int> GetValueTuple()
{
    return (X, Y);
}

然后像这样在 switch case 中调用方法。

case Size size:
     xy = size.GetValueTuple();
     break;
case Point point:
     xy = point.GetValueTuple();
     break;

没有到 ValueTuple 的隐式转换,并且您的赋值没有调用解构。您实质上是在尝试执行以下不合法的操作:

xy = (ValueTuple<int, int>)size;

您需要两个变量,而不是一个。如果您认为解构只是调用 Deconstruct 方法的编译器 trickery/syntactic 糖,这一点就更明显了。如果你打算手动调用它,你需要传递两个变量作为out参数,而不是一个。

int x, y;
size.Deconstruct(out x, out y);

没有采用 单个 元组的重载。那将如何工作?只有一个变量。我想您可能认为编译器 可以 做一些类似于:

size.Deconstruct(out xy.Item1, out xy.Item2);

不幸的是它没有。对于您的情况,您需要单独声明变量(而不是 ValueTuple),然后使用解构和元组语法来分配给它们。如果您愿意,可以将 default 案例中的赋值移出 switch ,以使两个变量的声明具有更多元组的感觉:

var (x, y) = (0, 0); // two variables 
switch (deconstructableStruct)
{
    case Size size:
        (x, y) = size;
        break;
    case Point point:
        (x, y) = point;
        break;
}

你以后仍然可以打开值,你只需要使用元组语法:

return (x, y) switch {
    (0, 0) => "Empty", 
    (0, _) => "Extremely narrow", 
    (_, 0) => "Extremely wide",
     _ => "Normal" 
};

请参阅 以获得更好的选择:如果您 确实 需要一个元组类型的变量,请编写您自己的 implicit 转换运算符它拥有(并且你们都能够并且不介意修改 SizePoint 类型以添加​​此行为)。

您的代码示例太复杂了。该问题与通用方法或 switch 无关。以下足以重现问题:

var size = new Size(4, 0);
(int, int) xy;

xy = size;

具体解释了为什么这种语法不起作用。当然,这实际上只是归结为语法错误。您只是没有正确编写代码。如果您真的不需要局部变量是元组类型,那么该答案提供了一个很好的选择。

也就是说,如果您能够更改 PointSize 类型,也可以使用元组类型变量实现您想要的。您可以简单地提供错误消息解释的当前不存在的隐式转换。例如,您可以将以下内容添加到 Size 类型:

public static implicit operator (int x, int y)(Size size)
{
    return (size.W, size.H);
}

那么赋值就会随心所欲地在任何地方工作,而不仅仅是在 switch 语句中。

您可以从每种类型的部分创建一个元组:

    case Size size:
        xy = (size.Length, size.Height);
        break;
    case Point point:
        xy = (point.X, point. Y);
        break;