I have a method using a long string of if/elseif statements (about 10-15), and I understand that when you get past about 5 if/else if statements, it's better to use a switch. That being said, I'm not sure that I can use a switch statement in my case, because my if/else if statements rely on testing a string, not for equality, but using the Contains() method. So, right now I have something equivalent of
string s = "ABCD";
if(s.Contains("A")
{
//do stuff
}
else if(s.Contains("E")
{
//do different stuff
}
etc ...
I've tried differnt ways of implementing the switch statement, such as
switch()
{
case(s.Contains("A"))
{
//do stuff
}
}
But each way I've tried results in a syntax error.
Is there a way to use a switch statement while still testing the string using the Contains() method?
No, switch
statements require constant values for the case labels. So in general you'd be better off sticking with the if
statements. But this is about as close as you can get to using a switch
statement for your scenario.
string myString = "ABC";
List<string> subStrings = new List<string>{"A", "B", "C"};
switch (subStrings.FirstOrDefault(myString.Contains))
{
case "A":
Console.WriteLine("Has A");
break;
case "B":
Console.WriteLine("Has B");
break;
case "C":
Console.WriteLine("Has C");
break;
default:
Console.WriteLine("No ABC");
break;
}
I doubt that would be any faster than the if
statements, because the FirstOrDefault
is basically doing the same thing, and it breaks the DRY principal as it requires updates to the list and switch
statement.
The first thing that comes to mind is
string s = "ABCD";
foreach (char oneChar in s.ToCharArray())
{
switch (oneChar)
{
case 'A':
Console.WriteLine("Do A stuff");
break;
case 'B':
Console.WriteLine("Do B stuff");
break;
case 'C':
Console.WriteLine("Do C stuff");
break;
case 'D':
Console.WriteLine("Do D stuff");
break;
default:
break;
}
}
depending on what you are doing, that may or may not be an efficient way to go. If a majority of the characters in the string actually cause a branch to one of these cases, this is much more efficient as you will not be having to do a bunch of string contains searches. If there are a lot of characters in the string that have no matching branch (they do nothing), then this is probably not an efficient way to go.
having a ton of if/else checks for specific stuff, usually alerts me of a good place to use enumerables for flexibility later if you can use it in your scenario. i'd probably do something like this:
string input = "ABDE";
var mapping = new Dictionary<Func<string, bool>, Action<string>>()
{
{ (string i) => i.Contains("A"), (string i) => Console.WriteLine("Found input with 'A'") },
{ (string i) => i.Contains("B"), (string i) => Console.WriteLine("Found input with 'B'") },
{ (string i) => i.Contains("C"), (string i) => Console.WriteLine("Found input with 'C'") },
{ (string i) => i.Contains("D"), (string i) => Console.WriteLine("Found input with 'D'") }
};
foreach (var criteria in mapping)
{
if (criteria.Key(input)) {
criteria.Value(input);
break;
}
}
That way the test/action conditions are grouped together, you can cleanly run over all the rules with a foreach without much work, and adding/removing rules is easier.
Using the pattern matching feature in C# 7.0, it is now possible to use Contains in switch statements. Provides much cleaner code than multiple if else blocks. The following code sample shows how to do it
var patterns = new[] { "dog", "cat", "cats and dogs", "parrot", "parrot and cat" };
foreach (var item in patterns)
{
switch (item)
{
case var s when s.Contains("cat"):
Console.WriteLine($"{item} contains cat");
break;
case var s when s.Contains("dog"):
Console.WriteLine($"{item} contains dog");
break;
case var s when s.Contains("parrot"):
Console.WriteLine($"{item} contains parrot");
break;
}
}
Please note, it won't work with versions earlier than C# 7.0.
If you have a LOT of these lines, sometimes it can be clearer and more flexible to use a dictionary to map the target values to actions, for example:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
public class Program
{
static void Main()
{
var dict = new Dictionary<string, Action<string>>
{
["A"] = Console.WriteLine,
["B"] = doSomething1,
["C"] = doSomething2,
["D"] = str => Console.WriteLine("Inline: " + str)
};
string s = "ABCD";
string first = dict.Keys.FirstOrDefault(t => s.Contains(t));
if (first != null)
dict[first](first);
else
; // Default behaviour.
}
private static void doSomething1(string x)
{
Console.WriteLine("doSomething1 with " + x);
}
private static void doSomething2(string x)
{
Console.WriteLine("doSomething2 with " + x);
}
}
}
By "more flexible" I mean that you can pass the dictionary around, should you want to map the actions in one place and use it somewhere else.
(This uses C# 6 syntax to initialise the dictionary.)
Having said all that, it seems to me an unneccessary complication UNLESS you want to pass the dictionary around. If you don't, then just using an if/else cascade would probably be the best approach.
(Note: This answer is similar to Mike Corcoran's - I was writing it at the same time he was his, it seems. I'll leave it here since it takes a slightly different approach.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.