我想使用一个带有几个变量的switch语句,如下所示:
switch (intVal1, strVal2, boolVal3)
{
case 1, "hello", false:
break;
case 2, "world", false:
break;
case 2, "hello", false:
etc ....
}
有没有办法在C#中做这样的事情? (出于显而易见的原因,我不想使用嵌套的switch语句。)
答案 0 :(得分:15)
您可以使用when
关键字在C#7及更高版本中执行此操作:
switch (intVal1)
{
case 1 when strVal2 == "hello" && boolVal3 == false:
break;
case 2 when strVal2 == "world" && boolVal3 == false:
break;
case 2 when strVal2 == "hello" && boolVal3 == false:
break;
}
答案 1 :(得分:12)
让我们看看另一种方式。如果你有:
int
,bool
,string
等。)然后您可以使用查找表,它具有与switch
语句类似的执行速度,但效率不高(因为它需要计算哈希值)。不过,它可能还不错。并且它为您提供了命名案例的机会,使这种组合爆炸稍微减少混乱和不可维护。
代码示例:
private static readonly Tuple<int, int, bool> NameOfCase1 =
Tuple.Create(1, 1, false);
private static readonly Tuple<int, int, bool> NameOfCase2 =
Tuple.Create(2, 1, false);
private static readonly Tuple<int, int, bool> NameOfCase3 =
Tuple.Create(2, 2, false);
private static readonly Dictionary<Tuple<int, int, bool>, string> Results =
new Dictionary<Tuple<int, int, bool>, string>
{
{ NameOfCase1, "Result 1" },
{ NameOfCase2, "Result 2" },
{ NameOfCase3, "Result 3" }
};
public string GetResultForValues(int x, int y, bool b)
{
const string defaultResult = "Unknown";
var lookupValue = Tuple.Create(x, y, b);
string result;
Results.TryGetValue(lookupValue, out result);
return defaultResult;
}
如果您需要为每个案例实际执行一个函数或方法,那么您可以使用Action<T>
或Func<T>
的结果类型(字典值)。
请注意,我在这里使用Tuple<T1,T2,T3>
因为它已经内置了所有哈希代码逻辑。语法在C#中有点尴尬但是如果你愿意,你可以实现自己的查找类而且只是覆盖Equals
和GetHashCode
。
答案 2 :(得分:10)
在C#中没有内置功能可以执行此操作,我不知道有任何库可以执行此操作。
以下是另一种方法,使用Tuple
和扩展方法:
using System;
static class CompareTuple {
public static bool Compare<T1, T2, T3>(this Tuple<T1, T2, T3> value, T1 v1, T2 v2, T3 v3) {
return value.Item1.Equals(v1) && value.Item2.Equals(v2) && value.Item3.Equals(v3);
}
}
class Program {
static void Main(string[] args) {
var t = new Tuple<int, int, bool>(1, 2, false);
if (t.Compare(1, 1, false)) {
// 1st case
} else if (t.Compare(1, 2, false)) {
// 2nd case
} else {
// default
}
}
}
这基本上只是提供一种方便的语法来检查多个值 - 并使用多个ifs而不是开关。
答案 3 :(得分:6)
我对此非常疯狂:
class Program
{
static void Main(string[] args)
{
var i = 1;
var j = 34;
var k = true;
Match(i, j, k).
With(1, 2, false).Do(() => Console.WriteLine("1, 2, 3")).
With(1, 34, false).Do(() => Console.WriteLine("1, 34, false")).
With(x => i > 0, x => x < 100, x => x == true).Do(() => Console.WriteLine("1, 34, true"));
}
static Matcher<T1, T2, T3> Match<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
{
return new Matcher<T1, T2, T3>(t1, t2, t3);
}
}
public class Matcher<T1, T2, T3>
{
private readonly object[] values;
public object[] Values
{
get { return values; }
}
public Matcher(T1 t1, T2 t2, T3 t3)
{
values = new object[] { t1, t2, t3 };
}
public Match<T1, T2, T3> With(T1 t1, T2 t2, T3 t3)
{
return new Match<T1, T2, T3>(this, new object[] { t1, t2, t3 });
}
public Match<T1, T2, T3> With(Func<T1, bool> t1, Func<T2, bool> t2, Func<T3, bool> t3)
{
return new Match<T1, T2, T3>(this, t1, t2, t3);
}
}
public class Match<T1, T2, T3>
{
private readonly Matcher<T1, T2, T3> matcher;
private readonly object[] matchedValues;
private readonly Func<object[], bool> matcherF;
public Match(Matcher<T1, T2, T3> matcher, object[] matchedValues)
{
this.matcher = matcher;
this.matchedValues = matchedValues;
}
public Match(Matcher<T1, T2, T3> matcher, Func<T1, bool> t1, Func<T2, bool> t2, Func<T3, bool> t3)
{
this.matcher = matcher;
matcherF = objects => t1((T1)objects[0]) && t2((T2)objects[1]) && t3((T3)objects[2]);
}
public Matcher<T1, T2, T3> Do(Action a)
{
if(matcherF != null && matcherF(matcher.Values) || matcher.Values.SequenceEqual(matchedValues))
a();
return matcher;
}
}
答案 4 :(得分:4)
您可以转换为字符串:
switch (intVal1.ToString() + strVal2 + boolVal3.ToString())
{
case "1helloFalse":
break;
case "2worldFalse":
break;
case "2helloFalse":
etc ....
}
我认为要发挥的问题是,是否有更好的方法来定义逻辑。例如,假设你想弄清楚谁知道超人。我们可以这样检查:
switch (first + last)
{
case "ClarkKent":
case "LoisLane":
// YES
break;
default;
// Sadly, no
break;
}
但是当你得到一个名叫克拉克肯特的其他人时会发生什么?你真的不能拥有一些其他的价值来确定这个逻辑,即bool KnowsSuperman?
这个想法是,switch语句用于根据一组选择来确定逻辑。如果你想要关闭多个值,那么逻辑可能难以维持下线。
另一个例子是,如果你需要将人们分成几个小组,并根据他们所在的小组执行一些逻辑。如果你是鲍勃,杰夫,吉姆或莎莉,你可以编写代码说,你在A组,但如果你需要将其他人添加到A组怎么办?你必须改变代码。相反,您可以创建一个名为Group的额外属性,该属性可以是枚举或字符串,您可以使用它来指定某人所在的组。
答案 5 :(得分:2)
2018年更新。自C#7.0起,Microsoft为交换机引入了“when”子句,使其可以有效地扩展具有附加条件的交换机案例。
答案 6 :(得分:2)
如果要切换多个输入并返回值,在C#8中,可以使用tuple patterns。这是模式匹配开关表达式的一种形式,它以元组的形式将多个值作为输入。这是使用您的输入的示例;请注意在默认情况下使用_
:
string result = (intVal1, strVal2, boolVal3) switch
{
(1, "hello", false) => "Combination1",
(2, "world", false) => "Combination2",
(2, "hello", false) => "Combination3",
_ => "Default"
};
这是上面链接的MSDN文章中的一个更具说明性的示例(石头,剪刀,剪刀游戏):
public static string RockPaperScissors(string first, string second)
=> (first, second) switch
{
("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie"
};
答案 7 :(得分:1)
根据C#语言规范,switch
语句表达式必须解析为sbyte, byte, sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type之一。这意味着您无法启用Tuple
或其他更高阶类型。
假设有空间,您可以尝试将值组合在一起。例如,假设每个整数保证在0..9。
范围内switch (intVal1 * 100 + intVal2 * 10 + (boolVal3 ? 1 : 0))
{
case 100: /* intVal1 = 1, intVal2 = 0, boolVal3 = false */ ... break;
case 831: /* intVal1 = 8, intVal2 = 3, boolVal3 = true */ ... break;
}
答案 8 :(得分:0)
据我所知,你不能用C#做到这一点。
但您可以从MSDN执行此操作:
以下示例显示,对于空案例标签,允许从一个案例标签到另一个案例标签:
switch(n)
{
case 1:
case 2:
case 3:
Console.WriteLine("It's 1, 2, or 3.");
break;
default:
Console.WriteLine("Not sure what it is.");
break;
}
答案 9 :(得分:0)
if (a == 1 && b == 1) {}
else if (a == 1 && b == 2) {}
else if (a == 2 && b ==2) {}
答案 10 :(得分:0)
我用列表或数组做这种事情。如果您可以枚举可能的条件(如果您想要进行多值切换,显然可以这样做),然后使用多部分键和Action
或Func<T>
构建查找表作为价值。
简单版本将使用Dictionary
:
class LookupKey: IComparable<LookupKey>
{
public int IntValue1 { get; private set; }
public int IntValue2 { get; private set; }
public bool BoolValue1 { get; private set; }
public LookupKey(int i1, int i2, bool b1)
{
// assign values here
}
public int Compare(LookupKey k1, LookupKey k2)
{
return k1.IntValue1 == k2.IntValue1 &&
k1.IntValue2 == k2.IntValue2 &&
k1.BoolValue1 == k2.BoolValue1;
}
public int GetHashCode()
{
return (19 * IntValue1) + (1000003 * IntValue2) + (BoolValue1) ? 0 : 100000073;
}
// need to override Equals
}
你的词典:
static readonly Dictionary<LookupKey, Action<object>> LookupTable;
然后,您可以在启动时填充字典,然后查找变得简单:
Action<object> MethodToCall;
if (LookupTable.TryGetValue(new LookupKey(i1, i2, b1), out MethodToCall)
MethodToCall(theData);
else
// default action if no match
这是设置的一些代码,但它的执行速度非常快。
答案 11 :(得分:0)
//.Net Core 3.1
class Convertors
{
static void Main(string[] args)
{
Console.WriteLine(Convertors.ConvertAny("m","cm", 10));
Console.ReadKey();
}
public static double MToCM(double value)
{
return value * 100;
}
public static double ConvertAny(string srcUOM, string tgtUOM, double value)
{
switch (srcUOM.ToLower(), tgtUOM.ToLower())
{
case ("m", "cm"): return Convertors.MToCM(value);
default: throw new NotImplementedException();
}
}
}