如何使 C# switch 语句使用 IgnoreCase?
如果我有一个 switch-case 语句,其中 switch 中的对象是字符串,是否可以进行 IgnoreCase 比较?
例如,我有:
string s = "house";
switch (s)
{
case "houSe": s = "window";
}
s
会得到值“window”吗?
如何覆盖 switch-case 语句,以便它使用 IgnoreCase 比较字符串?
If I have a switch-case statement where the object in the switch is a string, is it possible to do an IgnoreCase compare?
I have for instance:
string s = "house";
switch (s)
{
case "houSe": s = "window";
}
Will s
get the value "window"?
How do I override the switch-case statement so it will compare the strings using IgnoreCase?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
一种更简单的方法是在进入 switch 语句之前将字符串小写,并将大小写降低。
实际上,从纯粹的极端纳秒性能角度来看,Upper 稍好一些,但看起来不太自然。
例如:
A simpler approach is just lowercasing your string before it goes into the switch statement, and have the cases lower.
Actually, upper is a bit better from a pure extreme nanosecond performance standpoint, but less natural to look at.
E.g.:
对于这个老问题的新帖子,我们深表歉意,但是有一个新选项可以使用 C# 7 (VS 2017) 解决此问题。
C# 7 现在提供“模式匹配”,它可以用来解决这个问题:
这个解决方案还解决了 @Jeffrey L Whitledge 的答案中提到的问题,即字符串的不区分大小写的比较与比较两个字符串不同小写字符串。
顺便说一句,2017 年 2 月,Visual Studio 杂志上有一篇有趣的文章,描述了模式匹配以及如何在 case 块中使用它。请看一下:C# 7.0 Case Blocks 中的模式匹配
编辑
根据@LewisM 的回答,需要指出的是
switch
语句有一些新的、有趣的行为。也就是说,如果您的case
语句包含变量声明,则switch
部分中指定的值将复制到case
中声明的变量中。在以下示例中,值true
被复制到局部变量b
中。除此之外,变量b
未使用,并且仅存在以便case
语句的when
子句可以存在:正如 @LewisM 指出的出来,这可以用来带来好处 - 好处是被比较的东西实际上在
switch
语句中,就像switch
语句的经典使用一样。此外,在case
语句中声明的临时值可以防止对原始值进行不必要或无意的更改:Sorry for this new post to an old question, but there is a new option for solving this problem using C# 7 (VS 2017).
C# 7 now offers "pattern matching", and it can be used to address this issue thusly:
This solution also deals with the issue mentioned in the answer by @Jeffrey L Whitledge that case-insensitive comparison of strings is not the same as comparing two lower-cased strings.
By the way, there was an interesting article in February 2017 in Visual Studio Magazine describing pattern matching and how it can be used in case blocks. Please have a look: Pattern Matching in C# 7.0 Case Blocks
EDIT
In light of @LewisM's answer, it's important to point out that the
switch
statement has some new, interesting behavior. That is that if yourcase
statement contains a variable declaration, then the value specified in theswitch
part is copied into the variable declared in thecase
. In the following example, the valuetrue
is copied into the local variableb
. Further to that, the variableb
is unused, and exists only so that thewhen
clause to thecase
statement can exist:As @LewisM points out, this can be used to benefit - that benefit being that the thing being compared is actually in the
switch
statement, as it is with the classical use of theswitch
statement. Also, the temporary values declared in thecase
statement can prevent unwanted or inadvertent changes to the original value:正如您似乎知道的那样,小写两个字符串并比较它们与进行忽略大小写比较不同。这有很多原因。例如,Unicode 标准允许使用多种方式对带有变音符号的文本进行编码。某些字符在单个代码点中同时包含基本字符和变音符号。这些字符也可以表示为基本字符,后跟组合变音符号。这两种表示形式在所有用途上都是相等的,并且 .NET Framework 中的区域性感知字符串比较将使用 CurrentCulture 或 InvariantCulture(带或不带 IgnoreCase)正确地将它们识别为相等。另一方面,序数比较会错误地认为它们不相等。
不幸的是,
switch
除了序数比较之外不执行任何操作。序数比较适用于某些类型的应用程序,例如使用严格定义的代码解析 ASCII 文件,但序数字符串比较对于大多数其他用途来说是错误的。我过去为获得正确行为所做的只是模拟我自己的 switch 语句。有很多方法可以做到这一点。一种方法是创建一个由案例字符串和委托对组成的
List
。可以使用适当的字符串比较来搜索该列表。当找到匹配时,可以调用关联的委托。另一种选择是执行明显的
if
语句链。这通常并不像听起来那么糟糕,因为结构非常规则。这样做的好处是,在与字符串进行比较时,模拟您自己的开关功能实际上并没有任何性能损失。系统不会像处理整数那样创建 O(1) 跳转表,因此无论如何它都会一次比较每个字符串。
如果有很多情况需要比较,并且性能是一个问题,那么上面描述的
List
选项可以用排序字典或哈希表代替。那么性能可能会匹配或超过 switch 语句选项。以下是委托列表的示例:
当然,您可能需要向 CustomSwitchDestination 委托添加一些标准参数以及可能的返回类型。而且您会想起更好的名字!
如果您的每个案例的行为不适合以这种方式委托调用,例如如果需要不同的参数,那么您将陷入链式
if
语句的困境。我也这样做过几次。As you seem to be aware, lowercasing two strings and comparing them is not the same as doing an ignore-case comparison. There are lots of reasons for this. For example, the Unicode standard allows text with diacritics to be encoded multiple ways. Some characters includes both the base character and the diacritic in a single code point. These characters may also be represented as the base character followed by a combining diacritic character. These two representations are equal for all purposes, and the culture-aware string comparisons in the .NET Framework will correctly identify them as equal, with either the CurrentCulture or the InvariantCulture (with or without IgnoreCase). An ordinal comparison, on the other hand, will incorrectly regard them as unequal.
Unfortunately,
switch
doesn't do anything but an ordinal comparison. An ordinal comparison is fine for certain kinds of applications, like parsing an ASCII file with rigidly defined codes, but ordinal string comparison is wrong for most other uses.What I have done in the past to get the correct behavior is just mock up my own switch statement. There are lots of ways to do this. One way would be to create a
List<T>
of pairs of case strings and delegates. The list can be searched using the proper string comparison. When the match is found then the associated delegate may be invoked.Another option is to do the obvious chain of
if
statements. This usually turns out to be not as bad as it sounds, since the structure is very regular.The great thing about this is that there isn't really any performance penalty in mocking up your own switch functionality when comparing against strings. The system isn't going to make a O(1) jump table the way it can with integers, so it's going to be comparing each string one at a time anyway.
If there are many cases to be compared, and performance is an issue, then the
List<T>
option described above could be replaced with a sorted dictionary or hash table. Then the performance may potentially match or exceed the switch statement option.Here is an example of the list of delegates:
Of course, you will probably want to add some standard parameters and possibly a return type to the CustomSwitchDestination delegate. And you'll want to make better names!
If the behavior of each of your cases is not amenable to delegate invocation in this manner, such as if differnt parameters are necessary, then you’re stuck with chained
if
statments. I’ve also done this a few times.@STLDev 的回答的扩展。
从 C# 7 开始,一种无需多个 if 语句即可执行语句评估的新方法是使用模式匹配 switch 语句,类似于 @STLDev,但这种方法是切换要切换的变量。
Visual Studio 杂志有一篇关于模式匹配大小写块的好文章 这可能值得一看。
An extension to the answer by @STLDev.
A new way to do statement evaluation without multiple if statements as of C# 7 is using the pattern matching
switch
statement, similar to the way @STLDev though this way is switching on the variable being switched.The Visual Studio Magazine has a nice article on pattern matching case blocks that might be worth a look.
在某些情况下,使用枚举可能是个好主意。因此,首先解析枚举(使用ignoreCase标志为true),然后在枚举上进行切换。
In some cases it might be a good idea to use an enum. So first parse the enum (with ignoreCase flag true) and than have a switch on the enum.
一种可能的方法是将忽略大小写字典与操作委托一起使用。
// 请注意,调用不返回文本,而仅填充局部变量 s。
// 如果要返回实际文本,请将
Action
替换为Func
并将字典中的值替换为() =>; “窗口2”
One possible way would be to use an ignore case dictionary with an action delegate.
// Note that the call doesn't return text, but only populates local variable s.
// If you want to return the actual text, replace
Action
toFunc<string>
and values in dictionary to something like() => "window2"
我想说的是 切换表达式 (在 C# 8.0 中添加),丢弃模式和 本地函数由@STLDev和@LewisM 可以用更干净/更短的方式重写:
I would say that with switch expressions (added in C# 8.0), discard patterns and local functions the approaches suggested by @STLDev and @LewisM can be rewritten in even more clean/shorter way:
现在您可以使用开关表达式(重写前面的示例):
Now you can use the switch expression (rewrote the previous example):
这是一个将 @Magnus 的解决方案包装在一个类中的解决方案:
这是在简单的 Windows 窗体应用程序中使用它的示例:
如果您使用 lambda(如示例),您将获得闭包,它将捕获您的局部变量(非常接近你从 switch 语句中得到的感觉)。
由于它在幕后使用字典,因此它的行为复杂度为 O(1),并且不依赖于遍历字符串列表。当然,您需要构建该字典,这可能会花费更多。如果您想反复重用 Switch 行为,您可以创建并初始化一次 SwitchCaseIndependent 对象,然后根据需要多次使用它。
添加一个简单的
bool ContainsCase(string aCase)
方法来简单地调用字典的ContainsKey
方法可能是有意义的。Here's a solution that wraps @Magnus 's solution in a class:
Here's an example of using it in a simple Windows Form's app:
If you use lambdas (like the example), you get closures which will capture your local variables (pretty close to the feeling you get from a switch statement).
Since it uses a Dictionary under the covers, it gets O(1) behavior and doesn't rely on walking through the list of strings. Of course, you need to construct that dictionary, and that probably costs more. If you want to reuse the Switch behavior over and over, you can create and initialize the the
SwitchCaseIndependent
object once and then use it as many times as you want.It would probably make sense to add a simple
bool ContainsCase(string aCase)
method that simply calls the dictionary'sContainsKey
method.这样做应该足够了:
因此,开关比较是文化不变的。据我所知,这应该达到与 C#7 模式匹配解决方案相同的结果,但更简洁。
It should be sufficient to do this:
The switch comparison is thereby culture invariant. As far as I can see this should achieve the same result as the C#7 Pattern-Matching solutions, but more succinctly.
尝试将整个字符串转换为特定的大小写,小写或大写,然后用它进行比较:
Try to convert the whole string into a particular case, either lower case or upper case, and then use it for comparison:
使用不区分大小写的比较:
比较字符串时忽略大小写。
有关更多详细信息,请访问此链接:在 C# 语句和表达式中切换大小写
Using the Case Insensitive Comparison:
Comparing strings while ignoring case.
for more detail Visit this link: Switch Case When In C# Statement And Expression