Let's say I have the following Enum
:
public enum Cases
{
One,
Two,
Three,
Four,
Five
}
And I would like to implement the following logic using switch
:
One => "one to three"
Two => "one to three"
Three => "one to three"
Four => "four"
Five => "five"
all others => throw an Exception
Before C# 8.0, I would have written my example using a classic switch statement:
Heads-up, if you don't know:
[Theory]
and[InlindeData]
are Attributes used byxunit
, a dotnet testing framework. You can ignore it, it's not important to the discussion I would like to initiate. (I had to make sure that my logic is correct, before we can discuss, right ๐)
[Theory]
[InlineData(Cases.One, "one to three")]
[InlineData(Cases.Two, "one to three")]
[InlineData(Cases.Three, "one to three")]
[InlineData(Cases.Four, "four")]
[InlineData(Cases.Five, "five")]
public void SwitchStatement(Cases? input, string expected)
{
string actual;
switch (input)
{
case Cases.One:
case Cases.Two:
case Cases.Three:
actual = "one to three";
break;
case Cases.Four:
actual = "four";
break;
case Cases.Five:
actual = "five";
break;
default:
throw new InvalidEnumArgumentException();
}
Assert.Equal(expected, actual);
}
With C# 8.0 we did get switch expressions. Now we could write it like so:
[Theory]
[InlineData(Cases.One, "one to three")]
[InlineData(Cases.Two, "one to three")]
[InlineData(Cases.Three, "one to three")]
[InlineData(Cases.Four, "four")]
[InlineData(Cases.Five, "five")]
public void SwitchExpression(Cases? input, string expected)
{
var actual = input switch
{
Cases.One => "one to three",
Cases.Two => "one to three",
Cases.Three => "one to three",
Cases.Four => "four",
Cases.Five => "five",
_ => throw new InvalidEnumArgumentException()
};
Assert.Equal(expected, actual);
}
Or we can also combine cases One
, Two
and Three
using when
:
[Theory]
[InlineData(Cases.One, "one to three")]
[InlineData(Cases.Two, "one to three")]
[InlineData(Cases.Three, "one to three")]
[InlineData(Cases.Four, "four")]
[InlineData(Cases.Five, "five")]
public void SwitchExpressionWhen(Cases input, string expected)
{
var actual = input switch
{
var x when x == Cases.One || x == Cases.Two || x == Cases.Three => "one to three",
Cases.Four => "four",
Cases.Five => "five",
_ => throw new InvalidEnumArgumentException()
};
Assert.Equal(expected, actual);
}
We could also combine 1 to 3 using when
in a diffrent variation using an Array and Contains()
:
[Theory]
[InlineData(Cases.One, "one to three")]
[InlineData(Cases.Two, "one to three")]
[InlineData(Cases.Three, "one to three")]
[InlineData(Cases.Four, "four")]
[InlineData(Cases.Five, "five")]
public void SwitchExpressionContains(Cases input, string expected)
{
var actual = input switch
{
var x when new[] {Cases.One, Cases.Two, Cases.Three}.Contains(x) => "one to three",
Cases.Four => "four",
Cases.Five => "five",
_ => throw new InvalidEnumArgumentException()
};
Assert.Equal(expected, actual);
}
โ Which one of the examples do you prefer? Which one is the most readable to you? Or do you have an even nicer variation to share?
๐ I would like to gather the results in a poll. Do you mind giving your vote?
M. Langhard@langhardC# switch - Which variation do you prefer?
dev.to/riscie/c-switcโฆ10:30 AM - 12 Mar 2020
Top comments (6)
Michael B mentioned a dictionary option (though I don't know what it has to do with the strategy pattern) - and I second that - it's quite easy to do it like this:
(names are shortened for brevity - Never do that on actual code!)
Since c# 7.0, you can throw an exception directly from inside a ternary condition because c# 7.0 supports throw expression.
However, the
switch
expression is a very powerful tool and has a potential to shorten and beautify what was once a big long mess ofcase: /* code */ break;
Thank you! I like the approach of using a dictionary. However this way you can not combine cases One to Three, right? In our example I would be fine with it, but If we would have many cases, I would kind of dislike it.
Yes, that will force you to write all the cases into the dictionary - and it is a shortcoming of this approach. There are advantages for both approaches, just choose the most appropriate one each time...
Very nice post.
My preference matches the exact order you wrote them. Last one is my favorite, first one is my least favorite, but I think they're all okay.
The later ones are more "functional", have less repetition, and look cleaner to me.
I feel the same.
Care to share a quick example?