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

问题描述 投票:0回答:3

我有两个带有Deconstruct()方法的结构(点和大小)。两者都返回(int,int)元组。

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

无法将类型'Size'隐式转换为'(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;
    }
}
c# switch-statement tuples c#-8.0
3个回答
1
投票

没有对ValueTuple的隐式转换,您的分配没有调用解构。您需要两个变量,而不是一个。如果您认为解构只是调用Deconstruct方法的编译器技巧,这将变得更加明显。如果要手动调用它,则需要将two变量作为out参数而不是一个参数传递。

size.Deconstruct(out x, out y);

不存在需要single元组的重载。那将如何工作?只有一个变量。我想您可能会认为编译器可以做一些类似于:

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

不幸的是,没有。对于您的情况,您需要分别声明变量(而不是将其声明为ValueTuple),然后使用解构方法将其分配给它们。

int x, y;
 ... 
(x, y) = size;

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

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

0
投票

您可以在结构内部添加此帮助程序方法,以根据需要返回ValueTuple。

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

然后在像这样的切换情况下调用该方法。

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

0
投票

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

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

xy = size;

This answer特别说明了为什么此语法无法工作。当然,这实际上归结为语法错误。您只是没有正确编写代码。如果您真的不需要将局部变量设为元组类型,则可以使用该答案。

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

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

然后,该分配将随您想在任何地方工作,而不仅限于switch语句。

© www.soinside.com 2019 - 2024. All rights reserved.