'Using .StartsWith in a Switch statement?
I'm working on a Switch statement and with two of the conditions I need to see if the values start with a specific value. The Switch statement does like this. The error says "cannot covert type bool to string".
Anyone know if I can use the StartsWith in a Switch or do I need to use If...Else statements?
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
case subArea.StartsWith("3*"):
case subArea.StartsWith("03*"):
return "123";
default:
return "ABCXYZ123";
}
Solution 1:[1]
EDIT: If you are using C# >= 7, take a look at this answer first.
You are switching a String
, and subArea.StartsWith()
returns a Boolean
, that's why you can't do it. I suggest you do it like this:
if (subArea.StartsWith("3*") || subArea.StartsWith("03*"))
return "123";
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
default:
return "ABCXYZ123";
}
The result will be the same.
Solution 2:[2]
Since C# 7 you can do the following:
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
case string s when s.StartsWith("3*"):
return "123";
case string s when s.StartsWith("03*"):
return "123";
default:
return "ABCXYZ123";
}
Solution 3:[3]
Thanks to the when clause, you can now do:
switch (subArea)
{
// Skipping regular cases with string literals
case string dummy
when subArea.StartsWith("3*") ||
subArea.StartsWith("03*"):
return "123";
default:
return "ABCXYZ123";
}
Solution 4:[4]
Since C# 9 you can do the following:
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
case { } when subArea.StartsWith("3*"):
case { } when subArea.StartsWith("03*"):
return "123";
default:
return "ABCXYZ123";
}
Solution 5:[5]
The case labels must be strings, since the switch expression is a string; however, StartsWith
returns a Boolean. I suggest handling these special cases in the default
section.
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
default:
if (subArea.StartsWith("3") || subArea.StartsWith("03")) {
return "123";
}
return "ABCXYZ123";
}
Also the star (*) is probably wrong, unless you want subArea
to contain it. StartWith
does not accept wildcards.
Alternatively you could use regex:
if (Regex.IsMatch(subArea, "^3|^03")) { // or "^(3|03)"
return "123";
}
where ^
means start of line and |
means or.
Solution 6:[6]
Joe kind of beat me to it, but here's another non-switch way of doing it, which essentially implements a pattern matching algorithm with a rule set.
private static string GetSomeStringOrOther(string subArea)
{
// Create a set of pattern matching functions...
Func<string, string, bool> matchEquals = (a, b) => a.Equals(b);
Func<string, string, bool> matchStarts = (a, b) => a.StartsWith(b);
// Create a rule set...
Tuple<string, string, Func<string, string, bool>>[] cases = new []
{
new Tuple<string, string, Func<string, string, bool>>("4100", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("4101", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("4102", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("4200", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("600A", "XWZ", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("3*", "123", matchStarts),
new Tuple<string, string, Func<string, string, bool>>("03*", "123", matchStarts),
};
// Look for a match...
foreach(var matchCase in cases)
{
if(matchCase.Item3(subArea, matchCase.Item1))
{
// Return if it matches...
return matchCase.Item2;
}
}
// Otherwise return the default...
return "ABCXYZ123";
}
Advantages
- If you need a new rule, it's easy to add to the rule set.
- If you need a new pattern matching function, again, easy to add.
- Doesn't need extensive rework if a rule changes.
Disadvantages
- Novice/Beginner and even some intermediate developers might not have a clue what's going on.
Improvements
- Replace
Tuple<string, string, Func<string, string, bool>>
with a semantic object that represents aRule
Solution 7:[7]
Just for fun, here's another solution that avoids the switch statement.
var map = new[] {
new { Value = "4100", StartsWith = false, Result="ABC" },
new { Value = "4101", StartsWith = false, Result="ABC" },
new { Value = "4102", StartsWith = false, Result="ABC" },
new { Value = "4200", StartsWith = false, Result="ABC" },
new { Value = "600A", StartsWith = false, Result="XWZ" },
new { Value = "3*", StartsWith = true, Result="123" },
new { Value = "03*", StartsWith = true, Result="123" },
};
var subarea = ... whatever ...;
var result = map.Where(e =>
{
if (e.StartsWith)
{
return subarea.StartsWith(e.Value);
}
else
{
return subarea == e.Value;
}
}
)
.Select(e => e.Result)
.FirstOrDefault() ?? "ABCXZ123";
The order in the array map
determines the priority, so that, for example, you can have an exact match on, say, "3*11", as well as a StartsWith
match on "3*", e.g.:
var map = new[] {
new { Value = "3*11", StartsWith = false, Result="ABC" },
new { Value = "4100", StartsWith = false, Result="ABC" },
new { Value = "4101", StartsWith = false, Result="ABC" },
new { Value = "4102", StartsWith = false, Result="ABC" },
new { Value = "4200", StartsWith = false, Result="ABC" },
new { Value = "600A", StartsWith = false, Result="XWZ" },
new { Value = "3*", StartsWith = true, Result="123" },
new { Value = "03*", StartsWith = true, Result="123" },
};
Solution 8:[8]
With LINQ, the nice answer by @seriesOne can be "simplified" a bit by replacing the foreach
and return
statements with:
// using System.Linq;
// Look for a match...
var result = cases
.Where(c => c.Item3(subArea, c.Item1))
.FirstOrDefault();
// Return the match or the default.
return result == null ? "ABCXYZ123" : result.Item2;
Solution 9:[9]
Since C# 9 you can also do something like this, with a switch expression instead of a statement:
return subArea switch
{
"4100" or "4101" or "4102" or "4200" => "ABC",
"600A" => "XWZ",
{ } when subArea.StartsWith("3*") || subArea.StartsWith("03*") => "123",
_ => "ABCXYZ123"
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Steve Rousseau |
Solution 3 | Pang |
Solution 4 | Nwy |
Solution 5 | |
Solution 6 | |
Solution 7 | Joe |
Solution 8 | |
Solution 9 | Robledo |