Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在switch语句中使用c#元组值类型_C#_Switch Statement_Tuples_C# 7.0 - Fatal编程技术网

如何在switch语句中使用c#元组值类型

如何在switch语句中使用c#元组值类型,c#,switch-statement,tuples,c#-7.0,C#,Switch Statement,Tuples,C# 7.0,我正在使用.NET4.7中新的元组值类型。在本例中,我尝试为元组的一个或多个事例创建一个switch语句: using System; namespace ValueTupleTest { class Program { static void Main(string[] args) { (char letterA, char letterB) _test = ('A','B'); Console.W

我正在使用.NET4.7中新的元组值类型。在本例中,我尝试为元组的一个或多个事例创建一个switch语句:

using System;
namespace ValueTupleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            (char letterA, char letterB) _test = ('A','B');
            Console.WriteLine($"Letter A: '{_test.letterA}', Letter B: '{_test.letterB}'");

            switch (_test)
            {
                case ('A', 'B'):
                    Console.WriteLine("Case ok.");
                    break;
            }

        }
    }
}
不幸的是,这没有编译


如何在switch语句中正确获取元组并生成大小写?

感谢您的回复

我决定放弃使用switch语句,转而使用旧的if/else语句

using System;

namespace ValueTupleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            (char letterA, char letterB) _test = ('A','B');
            Console.WriteLine($"Letter A: '{_test.letterA}', Letter B: '{_test.letterB}'");

            if (_test.letterA == 'A' && _test.letterB == 'B')
            {
                Console.WriteLine("Case A ok.");
            }
            else if (_test.letterA == 'D' && _test.letterB == '\0')
            {
                Console.WriteLine("Case D ok.");
            }

        }
    }
}
通过这种方式,我可以决定是否要测试元组中的所有值,并按照需要的顺序进行测试。我认为它的表现应该不会有太大的不同


如果有另一种方法将元组与switch语句结合使用,请随意给出一个示例

从技术上回答您的问题,您可以使用
when
检查元组的值:

(char letterA, char letterB) _test = ('A', 'B');
Console.WriteLine($"Letter A: '{_test.letterA}', Letter B: '{_test.letterB}'");

switch (_test)
{
    case var tuple when tuple.letterA == 'A' && tuple.letterB == 'B':
        Console.WriteLine("Case ok.");
        break;
    case var tuple when tuple.letterA == 'D' && tuple.letterB == '\0':
        Console.WriteLine("Case ok.");
        break;
}

但是,考虑使用<代码>如果版本,因为它可能是一个更可读和可理解的解决方案。 这个问题的另一面是单一责任。您的方法知道

A
B
D
\0
字符的含义,这违反了单一责任原则。
就OOP而言,最好将这些知识从主代码中分离到一个单独的方法中。
类似的东西可以让代码更干净一些:

private static bool IsCaseOk(char a, char b) 
{
    return (a == 'A' && b == 'B') || (a == 'D' && b == '\0'); // any logic here
}

public static void Main() 
{
    (char letterA, char letterB) _test = ('A', 'B');
    Console.WriteLine($"Letter A: '{_test.letterA}', Letter B: '{_test.letterB}'");

    if (IsCaseOk(_test.letterA, _test.letterB)) {
        Console.WriteLine("Case ok.");
    } else {
        Console.WriteLine("Case not ok.");
    }
}

如果这些字母在您的域中有任何意义,那么创建一个具有两个
char
属性的类并在其中封装该逻辑可能是一个更好的主意。

使用元组或模式匹配没有错。如果有什么区别的话,它们允许您编写更干净的代码,避免将逻辑传播到多个方法

C#7还不允许您匹配元组值。您也不能用
=
运算符比较两个元组。您可以使用
Equals
two比较两个值元组:

 if (_test.Equals(('A','B'))
{
    Console.WriteLine("Case A ok.");
}
else if (_test.Equals(('D','\0'))
{
    Console.WriteLine("Case D ok.");
}
看起来您正试图为解析器(?)创建一个状态匹配,该解析器匹配特定的模式。如果为所有情况指定不同的状态类,而不是使用单个元组,则可以使用模式匹配

您只需指定一个没有方法的IState接口,并在所有状态类中使用它,例如:

interface IMyState {};
public class StateA:IMyState{ public string PropA{get;set;} };
public class StateD:IMyState{ public string PropD{get;set;} };

...
IMyState _test= new StateD(...);

switch (_test)
{
    case StateA a: 
        Console.WriteLine($"Case A ok. {a.PropA}");
        break;
    case StateD d: 
        Console.WriteLine($"Case D ok. {d.PropD}");
        break;
    default :
        throw new InvalidOperationException("Where's my state ?");
}
a
d
变量是强类型变量,这意味着您无需向
IState
界面添加任何内容。它只是为了满足编译器的需要

通过对状态类型使用结构而不是类,您将获得与元组相同的内存优势。如果要使用解构,可以为每个类型添加
Deconstruct
方法,或者在单独的静态类中使用
Deconstruct
扩展方法。

大小写(…):的语法保留给将来的模式。请参见C#语言功能规范中描述的位置模式:

C#7.3引入了元组相等,这意味着您在问题中的最初想法几乎是正确的。您只需捕获正在比较的值,如下所示:

var _test = ('A','B');
switch (_test)
{
   case var t when t == ('A', 'B'):
   Console.WriteLine("Case ok.");
   break;
}

这只是给偶然发现这个问题的人的一个便条

C#8.0引入了在这种情况下非常有用的方法

现在您可以执行以下操作:

var测试=('A','B');
测试开关
{
('A','B')=>Console.WriteLine(“确定”),
('A',)=>Console.WriteLine(“第一部分正常”),
(u,'B')=>Console.WriteLine(“第二部分正常”),
_=>Console.WriteLine(“不正常”),
};

您不能将元组用作开关值,开关只接受常量值。@实际上,Gusman不仅如此。@YeldarKurmangaliyev如果您指的是要使用类型的新sintax,那么这些类型也可以被视为常量。@Gusman我的意思是当语法时
<当r.Height==r.Width
不是非常恒定时,代码>大小写矩形r:)模式匹配是功能性的,而不是OOP概念。匹配一个值是完全正确的,并且不会破坏SRP。检查中的
绑定到值
部分。如果有什么区别的话,这会使职责更容易分离。通过将
开关
分为两部分,单一的责任变成了两个不同的代码块。您不需要放弃元组,使用
\u test.Equals(('A','B'))
看起来您正在尝试为解析器实现一个状态机?您可以为此使用模式匹配,但不能使用元组如果比较标记为错误,则alt+enter/“升级到c#7.3”