我可以将 switch 语句与 string.Contains() 结合使用吗?

Can I use a switch statement in conjunction with string.Contains()?

我有一个使用一长串 if/elseif 语句(大约 10-15)的方法,我知道当你超过大约 5 个 if/else if 语句时,最好使用转变。话虽这么说,但我不确定我是否可以在我的案例中使用 switch 语句,因为我的 if/else if 语句依赖于测试字符串,不是为了相等,而是使用 Contains() 方法。所以,现在我有相当于

的东西
string s = "ABCD";
if(s.Contains("A")
{
    //do stuff
}
else if(s.Contains("E")
{
    //do different stuff
}
etc ...

我尝试过不同的方式来实现 switch 语句,例如

switch()
{
    case(s.Contains("A"))
    {
        //do stuff
    }
}

但我尝试过的每种方法都会导致语法错误。

有没有办法在使用 switch 语句的同时仍然使用 Contains() 方法测试字符串?

首先想到的是

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

取决于您在做什么,这可能是也可能不是有效的方法。如果字符串中的大多数字符实际上导致了这些情况之一的分支,那么这会更有效率,因为您不必执行一堆包含字符串的搜索。如果字符串中有很多字符没有匹配的分支(它们什么都不做),那么这可能不是一种有效的方法。

对特定内容进行大量 if/else 检查,通常会提醒我以后如果可以在您的场景中使用可枚举数以获得灵活性的好地方。我可能会这样做:

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

这样 test/action 条件被组合在一起,你可以用 foreach 干净地 运行 遍历所有规则而不需要太多工作,adding/removing 规则更容易。

否,switch 语句需要 case 标签的常量值。所以一般来说,你最好坚持使用 if 语句。但这与您在场景中使用 switch 语句差不多。

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

我怀疑这会比 if 语句快,因为 FirstOrDefault 基本上做同样的事情,它破坏了 DRY 原则,因为它需要更新列表和 switch声明。

如果你有很多这样的行,有时使用字典将目标值映射到动作会更清晰、更灵活,例如:

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

"more flexible" 我的意思是你可以传递字典,如果你想在一个地方映射动作并在其他地方使用它的话。

(这使用 C# 6 语法来初始化字典。)

说了这么多,在我看来这似乎是一个不必要的复杂化,除非你想传递字典。如果你不这样做,那么使用 if/else 级联可能是最好的方法。

(注意:这个答案与 Mike Corcoran 的相似 - 我似乎是在他是他的同时写的。我会把它留在这里,因为它采用了稍微不同的方法。)

使用 C# 7.0 中的 pattern matching feature,现在可以在 switch 语句中使用 Contains。提供比多个 if else 块更简洁的代码。下面的代码示例展示了如何做到这一点

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

请注意,它不适用于 C# 7.0 之前的版本。