如果我有一个包含字符串的switch-case语句,是否可以进行忽略大小写的比较?
我有例如:
string s = "house";
switch (s)
{
case "houSe": s = "window";
}
s
会得到值"window"吗?如何覆盖switch-case语句,以便使用ignoreCase来比较字符串?
如果我有一个包含字符串的switch-case语句,是否可以进行忽略大小写的比较?
我有例如:
string s = "house";
switch (s)
{
case "houSe": s = "window";
}
s
会得到值"window"吗?如何覆盖switch-case语句,以便使用ignoreCase来比较字符串?
如你所知,减少两条插图和比较,与忽视案例的比较不同。 原因很多。 例如,统法协会编码标准允许有二分法文本以多种方式编码。 某些特性既包括基质特性,也包括单一代码点的分辨率。 这些特性也可以作为基本特征来体现,随后是分属性。 这两种代表的目的都是平等的,而文化意识的比较则体现在其中。 联系网框架将正确地确定它们是平等的,既包括当前文化,也包括无IgnoreCase。 另一方面,如果比较晚,就会错误地认为不平等。
不幸的是,switch
除了进行顺序比较之外,什么也不做。顺序比较对于某些应用程序来说是可以的,比如解析具有严格定义代码的ASCII文件,但对于大多数其他用途来说,顺序字符串比较是不正确的。
为了得到正确的行为,我过去所做的就是模拟自己的switch语句。有很多方法可以做到这一点。其中一种方法是创建一个由案例字符串和委托对组成的List<T>
。可以使用正确的字符串比较来搜索列表。当找到匹配时,则可以调用关联的委托。
另一个选择是执行明显的if语句链。通常情况下,这不像听起来那么糟糕,因为结构非常规律。
这个太好了,因为与字符串比较的时候,自己模拟开关功能并不会有任何性能损失。系统不会像整数一样创建一个O(1)跳跃表,因此它将逐个比较每个字符串。
如果有许多案例需要进行比较,并且性能是一个问题,那么上面描述的 List<T>
选项可以被替换为排序字典或哈希表。然后性能可能会达到或超过 switch 语句选项。
这是代表名单的一个例子:
delegate void CustomSwitchDestination();
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList;
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound);
void CustomSwitch(string value)
{
foreach (var switchOption in customSwitchList)
if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase))
{
switchOption.Value.Invoke();
return;
}
defaultSwitchDestination.Invoke();
}
当然,您可能希望向CustomSwitchDestination委托添加一些标准参数和可能的返回类型。另外,您会想起更好的名称!
如果您的每个案例的行为不能以这种方式进行委托调用,例如如果需要不同的参数,则您必须使用链接的if语句。我也做过这几次。
if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase))
{
s = "window";
}
else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase))
{
s = "really big window";
}
else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase))
{
s = "broken window";
}
一个更简单的方法是在进入开关语句之前将字符串转换为小写,并使案例变小。
实际上,从纯极极端的纳米秒业绩角度看,上层情况较好,但不太自然。
例如:
string s = "house";
switch (s.ToLower()) {
case "house":
s = "window";
break;
}
抱歉为了一个旧问题发了一篇新帖子,不过现在有一个新选项可以使用C# 7(VS 2017)来解决这个问题。
C# 7现在提供了“模式匹配”,它可以用于解决此问题:
string houseName = "house"; // value to be tested, ignoring case
string windowName; // switch block will set value here
switch (true)
{
case bool b when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase):
windowName = "MyWindow";
break;
case bool b when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase):
windowName = "YourWindow";
break;
case bool b when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase):
windowName = "Window";
break;
default:
windowName = null;
break;
}
这个解决方案还解决了 @Jeffrey L Whitledge 的回答中提到的问题,即字符串大小写不敏感的比较与比较两个小写字符串不同。
顺便提一下,Visual Studio杂志2017年2月有一篇有趣的文章介绍了模式匹配及其在Case块中的应用。请查看:C# 7.0 Case Block中的模式匹配
编辑
根据@LewisM的答案,需要指出switch
语句具有一些新的有趣行为。也就是说,如果你的case
语句包含变量声明,那么在switch
中指定的值会被复制到case
中声明的变量中。在下面的例子中,值true
被复制到局部变量b
中。此外,变量b
未被使用,仅存在于when
子句中以便于case
语句存在:
switch(true)
{
case bool b when houseName.Equals("X", StringComparison.InvariantCultureIgnoreCase):
windowName = "X-Window";):
break;
}
正如@LewisM所指出的,这可以用于受益-受益在于被比较的事物实际上在switch
语句中,正如经典的switch
语句的使用方式。此外,在case
语句中声明的临时值可以防止对原始值进行不必要或无意的更改:
switch(houseName)
{
case string hn when hn.Equals("X", StringComparison.InvariantCultureIgnoreCase):
windowName = "X-Window";
break;
}
@STLDeveloperA的答案的延伸。在C# 7中,一种新的语句评估方法是使用模式匹配switch
语句,而不是多个if语句,类似于@STLDeveloper所想的那种在变量上切换的方式。
string houseName = "house"; // value to be tested
string s;
switch (houseName)
{
case var name when string.Equals(name, "Bungalow", StringComparison.InvariantCultureIgnoreCase):
s = "Single glazed";
break;
case var name when string.Equals(name, "Church", StringComparison.InvariantCultureIgnoreCase):
s = "Stained glass";
break;
...
default:
s = "No windows (cold or dark)";
break;
}
Visual Studio 杂志有一篇有关模式匹配 case 块的精彩文章,值得一读。
在某些情况下,使用枚举可能是一个好主意。所以首先解析枚举(忽略大小写标志为 true),然后切换到枚举。
SampleEnum Result;
bool Success = SampleEnum.TryParse(inputText, true, out Result);
if(!Success){
//value was not in the enum values
}else{
switch (Result) {
case SampleEnum.Value1:
break;
case SampleEnum.Value2:
break;
default:
//do default behaviour
break;
}
}
一个可能的方法是使用带有动作委托的忽略大小写的字典。
string s = null;
var dic = new Dictionary<string, Action>(StringComparer.CurrentCultureIgnoreCase)
{
{"house", () => s = "window"},
{"house2", () => s = "window2"}
};
dic["HouSe"]();
// Note that the call doesn t return text, but only populates local variable s.
// If you want to return the actual text, replace Action
to Func<string>
and values in dictionary to something like () => "window2"
这是一个将@Magnus的解决方案封装在类中的解决方案:
public class SwitchCaseIndependent : IEnumerable<KeyValuePair<string, Action>>
{
private readonly Dictionary<string, Action> _cases = new Dictionary<string, Action>(StringComparer.OrdinalIgnoreCase);
public void Add(string theCase, Action theResult)
{
_cases.Add(theCase, theResult);
}
public Action this[string whichCase]
{
get
{
if (!_cases.ContainsKey(whichCase))
{
throw new ArgumentException($"Error in SwitchCaseIndependent, "{whichCase}" is not a valid option");
}
//otherwise
return _cases[whichCase];
}
}
public IEnumerator<KeyValuePair<string, Action>> GetEnumerator()
{
return _cases.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _cases.GetEnumerator();
}
}
这里的一个例子是,在简单的Windows表格中使用它:
var mySwitch = new SwitchCaseIndependent
{
{"hello", () => MessageBox.Show("hello")},
{"Goodbye", () => MessageBox.Show("Goodbye")},
{"SoLong", () => MessageBox.Show("SoLong")},
};
mySwitch["HELLO"]();
如果您使用lambda表达式(例如),您将获得闭包,这些闭包将捕获您的本地变量(与switch语句的感觉非常接近)。
由于它在内部使用字典,它获得了O(1)的性能,并且不依赖于遍历字符串列表。当然,你需要构建那个字典,这可能会付出更多的代价。如果你想反复重用Switch行为,你可以创建和初始化SwitchCaseIndependent
对象一次,然后无论你想用多少次,都可以使用它。
可能有意义的是添加一个简单的bool ContainsCase(string aCase)
方法,它只是调用字典s的ContainsKey
方法。
我想说,使用在C# 8.0版本中增加的switch表达式、discard模式和局部函数,可以使@STLDev和@LewisM建议的方法更加简洁/简短:
string houseName = "house"; // value to be tested
// local method to compare, I prefer to put them at the bottom of the invoking method:
bool Compare(string right) => string.Equals(houseName, right, StringComparison.InvariantCultureIgnoreCase);
var s = houseName switch
{
_ when Compare("Bungalow") => "Single glazed",
_ when Compare("Church") => "Stained glass",
// ...
_ => "No windows (cold or dark)" // default value
};
这样应该就足够了。
string s = "houSe";
switch (s.ToLowerInvariant())
{
case "house": s = "window";
break;
}
该开关比较因此与文化无关。就我所知,这应该可以实现与C#7模式匹配解决方案相同的结果,但更加简洁。
我希望这有助于将整个扼杀物转化成具体案件,或将下级案例加以比较。
public string ConvertMeasurements(string unitType, string value)
{
switch (unitType.ToLower())
{
case "mmol/l": return (Double.Parse(value) * 0.0555).ToString();
case "mg/dl": return (double.Parse(value) * 18.0182).ToString();
}
}
Using the Case Insensitive Comparison: Comparing strings while ignoring case.
switch (caseSwitch)
{
case string s when s.Equals("someValue", StringComparison.InvariantCultureIgnoreCase):
// ...
break;
}
了解更多细节,请访问此链接:C#语句和表达式中的Switch Case When
现在你可以使用switch表达式(重写之前的示例):
return houseName switch
{
_ when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase) => "MyWindow",
_ when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase) => "YourWindow",
_ when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase) => "Window",
_ => null
};
What is the use of default keyword in C#? Is it introduced in C# 3.0 ?
I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...
I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...
I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...
I have two EF entities. One has a property called HouseNumber. The other has two properties, one called StartHouseNumber and one called EndHouseNumber. I want to create a many to many association ...
How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...
Since I cannot order my dictionary, what is the best way of going about taking key value pairs and also maintaing an index?
Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...