【问题标题】:Can I use a switch statement in conjunction with string.Contains()?我可以将 switch 语句与 string.Contains() 一起使用吗?
【发布时间】:2016-01-02 12:26:05
【问题描述】:

我有一个方法使用一长串 if/elseif 语句(大约 10 到 15 个),我知道当您超过大约 5 个 if/else if 语句时,最好使用 switch。话虽如此,我不确定是否可以在我的情况下使用 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
    }
}

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

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

【问题讨论】:

  • 不,switch 语句需要 case 标签的常量值。
  • 好的。我就是这么想的,但我想确定一下。谢谢!
  • @BrianH 您只想执行“命中”的第一个操作,还是字符串包含该子字符串的所有操作?
  • @Jonesopolis 只有 1 个子字符串适用。继续上面的示例,包含“A”的字符串永远不会包含“E”,反之亦然(也许我应该为上面构建一个更强大的示例)lol

标签: c# string switch-statement contains


【解决方案1】:

在 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 之前的版本。

【讨论】:

    【解决方案2】:

    不,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 语句。

    【讨论】:

    【解决方案3】:

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

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

    “更灵活”是指您可以传递字典,如果您想将操作映射到一个地方并在其他地方使用它。

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

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

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

    【讨论】:

    • 应该注意if(first != null)之后的else是处理“默认”情况的地方。
    【解决方案4】:

    有大量的 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;
        }
    }
    

    这样测试/操作条件组合在一起,您可以使用 foreach 干净地运行所有规则而无需太多工作,并且添加/删除规则更容易。

    【讨论】:

    • 要复制 if-else if-else 行为,您需要在第一场比赛中中断。如果没有匹配项能够处理“默认”情况,您必须跟踪。
    【解决方案5】:

    首先想到的是

            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-elseif 语句,除非这是您的代码中执行很多的点。有一些方法可以减少一些时钟滴答,但很可能不值得努力。
    猜你喜欢
    • 2019-06-17
    • 1970-01-01
    • 2015-09-21
    • 2022-01-14
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多