I would like use a switch statement which takes several variables and looks like this:
switch (intVal1, strVal2, boolVal3)
{
case 1, \"hello\", false:
You can do this in C# 7 and higher with the when keyword:
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;
}
My downright crazy take on this:
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;
}
}
if (a == 1 && b == 1) {}
else if (a == 1 && b == 2) {}
else if (a == 2 && b ==2) {}
Per the C# language specification, the switch
statement expression must resolve to one of sbyte, byte, sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type. This means you cannot switch on Tuple
or other higher-order types.
You could try to pack the values together, assuming there is room. For example, suppose each of the integers is guaranteed to be in the range 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;
}
You cannot do that in C# as far as I know.
But you can do this from MSDN:
The following sample shows that fall through from one case label to another is allowed for empty case labels:
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;
}
There is (was) no built-in functionality to do this in C#, and I don't know of any library to do this.
Here is an alternative approach, using Tuple
and extension methods:
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
}
}
}
This is basically doing nothing more than providing a convenient syntax to check for multiple values - and using multiple if
s instead of a switch
.