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";
            }

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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";
}

Method 2

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.

Method 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";
}

Method 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";
}

Method 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.

Method 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 a Rule

Method 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" },
};

Method 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;

Method 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"
        };


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x