Sof*_*lan 8 c# tuples switch-statement c#-7.0
我在.net 4.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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不编译.
如何正确地使用元组并在switch语句中创建案例?
Yel*_*yev 10
从技术上回答你的问题,你可以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;
}
Run Code Online (Sandbox Code Playgroud)
但是,请考虑使用if版本,因为它可能是一个更易读和易懂的解决方案.
这个问题的另一方面是单一责任.你的方法知道什么做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.");
}
}
Run Code Online (Sandbox Code Playgroud)
如果这些字母在你的域中有任何意义,那么甚至可能更好的想法是创建一个具有两个char属性的类并在那里封装这个逻辑.
对于偶然发现这个问题的人来说,这只是一个说明。
C# 8.0 引入了switch 表达式,这在这种情况下非常有用。
现在你可以做这样的事情:
var test = ('A', 'B');
test switch
{
('A', 'B') => Console.WriteLine("OK"),
('A', _) => Console.WriteLine("First part OK"),
( _, 'B') => Console.WriteLine("Second part OK"),
_ => Console.WriteLine("Not OK"),
};
Run Code Online (Sandbox Code Playgroud)
C#7.3引入了元组相等性,这意味着你在问题中的初步想法几乎是正确的.您只需捕获您正在比较的值,如下所示:
var _test = ('A','B');
switch (_test)
{
case var t when t == ('A', 'B'):
Console.WriteLine("Case ok.");
break;
}
Run Code Online (Sandbox Code Playgroud)
使用元组或模式匹配没有错.如果有的话,这些允许您编写更清晰的代码并避免将您的逻辑分散到多个方法.
C#7不允许您来匹配元组值还没有.您无法将两个元组与==运算符进行比较.你可以做的是使用Equals两个比较两个值元组:
if (_test.Equals(('A','B'))
{
Console.WriteLine("Case A ok.");
}
else if (_test.Equals(('D','\0'))
{
Console.WriteLine("Case D ok.");
}
Run Code Online (Sandbox Code Playgroud)
您似乎正在尝试为解析器(?)创建状态匹配,以匹配特定模式.如果指定不同的状态类而不是对所有情况使用单个元组,则这可以与模式匹配一起使用.
您需要做的就是指定一个没有方法的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 ?");
}
Run Code Online (Sandbox Code Playgroud)
的a,d变量是强类型的,这意味着你不必添加任何的IState接口.它只是为了满足编译器.
通过使用结构而不是状态类型的类,您将获得与元组相同的内存优势.如果要使用解构,可以Deconstruct为每种类型添加方法,或Deconstruct在单独的静态类中使用扩展方法.
感谢您的回复。
我决定放弃使用 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.");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样我就可以决定是否要按照我需要的顺序测试元组中的所有值。我认为性能上应该不会有太大差异。
如果还有另一种将元组与 switch 语句一起使用的方法,请随意举个例子。