C# 8 switch expression with multiple cases with same result
I got around to installing it, but I have not found a way to specify multiple, separate case labels for a single switch section with the new syntax.
However, you can create a new variable that captures the value and then use a condition to represent the cases that should have the same result:
var resultText = switchValue switch
{
var x when
x == 1 ||
x == 2 ||
x == 3 => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
This is actually more concise if you have many cases to test, because you can test a range of values in one line:
var resultText = switchValue switch
{
var x when x > 0 && x < 4 => "one to three",
4 => "four",
5 => "five",
_ => "unknown",
};
C# 8 switch expression: Handle multiple cases at once?
As of C#9, you can do exactly what you wanted via "disjunctive or
" patterns:
private static GameType UpdateGameType(GameType gameType) => gameType switch
{
GameType.RoyalBattleLegacy or GameType.RoyalBattleNew => GameType.RoyalBattle,
GameType.FfaLegacy or GameType.FfaNew => GameType.Ffa,
_ => gameType;
};
Further reading:
- What's new in C# 9.0: pattern matching enhancements
- Patterns C# reference
Multiple case in c# 8.0 switch expression
or operator in switch is not available in c# 8.0, it is available c# 9.0 or greater versions, in c# 8.0 you may solve as following:
static string CardinalToOrdinal(int number)
{
return number switch
{
11 => $"{ number}th",
12 => $"{ number}th",
13 => $"{ number}th",
_ => $"{number}" + number.ToString()[number.ToString().Length - 1]
switch
{
'1' => "st",
'2' => "nd",
_ => "th"
}
};
}
For more information, pls look to this article
Multiple statements in a switch expression: C# 8
Your only supported choice is the func like you did. See [this article][1] for more information. His example:
var result = operation switch
{
"+" => ((Func<int>)(() => {
Log("addition");
return a + b;
}))(),
"-" => ((Func<int>)(() => {
Log("subtraction");
return a - b;
}))(),
"/" => ((Func<int>)(() => {
Log("division");
return a / b;
}))(),
_ => throw new NotSupportedException()
};
Just because switch expressions are new doesn't mean they are the best for all use cases. They are not designed to contain multiple commands.
Edit: I suppose you could also simply call external functions instead of making anonymous ones.
[1]: https://alexatnet.com/cs8-switch-statement/
Multiple cases in switch statement
There is no syntax in C++ nor C# for the second method you mentioned.
There's nothing wrong with your first method. If however you have very big ranges, just use a series of if statements.
Multiple cases in switch statement with same alias
It rather depends on what the data type of rangeA
and rangeB
are.
Assuming they're object
, you can do something like this. It will throw an exception at runtime if you create a Range<Something non-comparable>
then call ContainsInclusive
on it. You can add an extra check for that if you want, but it gets a bit messy as Nullable<T>
doesn't implement any interfaces, so you'll have to resort to reflection.
public class Program
{
public static void Main()
{
Foo(new Range<int>() { ValueFrom = 1, ValueTo = 10 }, new Range<int>() { ValueFrom = 0, ValueTo = 10 });
Foo(new Range<int?>() { ValueFrom = 1, ValueTo = 10 }, new Range<int?>() { ValueFrom = 0, ValueTo = 10 });
}
private static bool Foo(object rangeA, object rangeB)
{
return (rangeA, rangeB) switch
{
(Range<int> a, Range<int> b) => b.ContainsInclusive(a),
(Range<int?> a, Range<int?> b) => b.ContainsInclusive(a),
_ => false,
};
}
}
public class Range<T>
{
public T ValueFrom { get; set; }
public T ValueTo { get; set; }
public bool ContainsInclusive(Range<T> other)
{
return Comparer<T>.Default.Compare(other.ValueFrom, this.ValueTo) <= 0 &&
Comparer<T>.Default.Compare(other.ValueTo, this.ValueFrom) >= 0;
}
}
If you can't use the new switch expressions in this way, you can potentially do something like:
private static bool Foo(object rangeA, object rangeB)
{
return TryContainsInclusive<int>(rangeA, rangeB) ||
TryContainsInclusive<int?>(rangeA, rangeB);
}
private static bool TryContainsInclusive<T>(object a, object b)
{
if (a is Range<T> rangeA && b is Range<T> rangeB)
{
return rangeB.ContainsInclusive(rangeA);
}
return false;
}
If rangeA
and rangeB
can be generic types, you can get away with the simpler:
private static bool Foo<T>(Range<T> rangeA, Range<T> rangeB)
{
return rangeB.ContainsInclusive(rangeA);
}
If rangeA
and rangeB
can be some base Range
type, then you can do something like this. Again, this will throw at runtime if T
isn't comparable:
public class Program
{
public static void Main()
{
Foo(new Range<int>() { ValueFrom = 1, ValueTo = 10 }, new Range<int>() { ValueFrom = 0, ValueTo = 10 }).Dump();
Foo(new Range<int?>() { ValueFrom = 1, ValueTo = 10 }, new Range<int?>() { ValueFrom = 0, ValueTo = 10 }).Dump();
}
private static bool Foo(Range rangeA, Range rangeB)
{
return rangeB.ContainsInclusive(rangeA);
}
}
public abstract class Range
{
public abstract bool ContainsInclusive(Range other);
}
public class Range<T> : Range
{
public T ValueFrom { get; set; }
public T ValueTo { get; set; }
public override bool ContainsInclusive(Range other)
{
if (other is Range<T> o)
{
return Comparer<T>.Default.Compare(o.ValueFrom, this.ValueTo) <= 0 &&
Comparer<T>.Default.Compare(o.ValueTo, this.ValueFrom) >= 0;
}
return false;
}
}
Using blocks in C# switch expression?
however I didn't understand where this is addressed in the documentation
This is stated pretty clear here:
There are several syntax improvements here:
- The variable comes before the switch keyword. The different order makes it visually easy to distinguish the switch expression from the
switch statement.- The case and : elements are replaced with =>. It's more concise and intuitive.
- The default case is replaced with a _ discard.
- The bodies are expressions, not statements.
{ someDir.Delete(); ... MoreActions}
is not an expression.
However, you can abuse every feature, as they say :)
You can make the switch expression evaluate to an Action
, and invoke that action:
Action a = response switch
{
"yes" => () => { ... },
_ => () => { .... }
};
a();
You can even reduce this to a single statement:
(response switch
{
"yes" => (Action)(() => { ... }),
_ => () => { ... }
})();
But just don't do this...
Related Topics
Entity Framework - Stored Procedure Return Value
How to Cast Expression<Func<T, Datetime>> to Expression<Func<T, Object>>
How to Programmatically List All Projects in a Solution
Writing to Then Reading from a Memorystream
Understanding Foreignkey Attribute in Entity Framework Code First
Performance Cost of 'Try' in C#
How Would It Be Possible to Remove All Event Handlers of the 'Click' Event of a 'Button'
Adding Custom Properties for Each Request in Application Insights Metrics
Static and Instance Methods with the Same Name
How to Initialize a Datetime Field
Foreach Control in Form, How to Do Something to All the Textboxes in My Form
What's the Difference Between Double Quotes and Single Quote in C#
Is This a Bad Practice to Catch a Non-Specific Exception Such as System.Exception? Why
Why Does This Simple .Net Console App Have So Many Threads
How to Programmatically Change Printer Settings with the Webbrowser Control