有没有其他的写法可以像这样:
if (a == x || a == y || a == z)
我发现一种方法就是像这样做:
if( new [] {x,y,z}.Contains(a))
还有其他好的方法吗?
我经常使用一个扩展方法来模拟SQL中的IN
:
public static bool IsIn<T>(this T obj, params T[] collection) {
return collection.Contains(obj);
}
那样我就可以做到
if(a.IsIn(b, c, d)) { ... }
params
真是太聪明了,点赞! - tzamana
为空,它将返回true,如果集合中的任何其他项为空,则返回true,但如果集合中没有其他项为空,则返回false。需要注意的是,您可以编写string a = null; a.IsIn("a","b")
,但您不能编写null.IsIn("a","b")
,因为在这种情况下无法推断类型。但是,无论如何编写都是荒谬的... - David HedlundSystem.Linq.Enumerable.Contains<T>()
,它可用于T[]
。您需要包含using System.Linq;
。 - David Hedlund你有经典的 switch 语句:
switch(a) {
case x:
case y:
case z:
// Do stuff
break;
}
仅供娱乐:
using System;
static class Program {
static bool In(this object obj, params object[] values) {
foreach (object value in values) {
if (obj.Equals(value)) {
return true;
}
}
return false;
}
static void Main(string[] args) {
bool test1 = 3.In(1, 2, 3);
bool test2 = 5.In(1, 2, 3);
}
}
但我真的认为最好的方法是撰写普通支票。
if(a == x || a == y || a == z)
每个人都能立刻理解它的作用。
您将其改写为的解决方案
if( new [] {x,y,z}.Contains(a))
这不是一个好的做法。
你把一个简单有效的逻辑操作转化为了需要一段时间才能理解且效率明显降低的代码。这个逻辑操作中包含了短路逻辑来提高效率,而你却没有保留它。
有时候,你的同事们会更喜欢你不要试图“聪明”!
Contains
仍然会短路。至少任何合理的实现都应该是这样的。 - Brian GideonContains
会进行短路操作,确保在找到匹配项后不会继续比较,但在Contains
开始之前,您需要初始化数组,并且此时访问x
、y
和z
。如果z
需要进行大量计算才能评估,并且a == x
,则在开始Contains
操作之前仍将评估z
。 - David Hedlundif(a == x || a == y || a == z)
中,您可以利用短路||
运算符的优势,这样y和z就不会被计算。new[] { x, y, z }
创建数组,则每次都会计算y和z。.Contains()
的“技巧”将更加实用,如果有一种优雅的语法来创建惰性求值序列(IEnumerable<T>
),即类似于yield return x; yield return y;...
但是内联和更短。
有趣的事实,自C#9起就可以实现这一点
var c ='b';
if (c is 'a' or 'b' or 'c')
Console.WriteLine("yes");
编译成
if (c == 'a' || c == 'b' || c == 'c')
{
Console.WriteLine("yes");
}
或者你可以更有创意一些
if (c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',')
Console.WriteLine("yes");
这段代码编译后大致会变成(在sharp io上)。
if (c >= 'a')
{
if (c <= 'z')
{
goto IL_0025;
}
}
else if (c >= 'A')
{
if (c <= 'Z')
{
goto IL_0025;
}
}
else if (c == ',' || c == '.')
{
goto IL_0025;
}
bool flag = false;
goto IL_002b;
IL_0025:
flag = true;
goto IL_002b;
IL_002b:
if (flag)
{
Console.WriteLine("yes");
}
或者在switch语句中使用它
switch (c)
{
case 'a' or 'b' or 'c':
Console.WriteLine("yes");
break;
}
所以,您想要替换一个包含短路优化的简单高效语言结构,改用一个潜在抛出异常的更慢的东西吗?
然而,如果您要比较的项目数量不是固定的,即在运行时可能是t、u、v、w、x、y、z等等,则Collection.Contains方法是唯一的选择,但这样您将传递集合对象而不是单个值,因此几乎没有内存分配开销。
如果您有大量要与'a'进行比较的项目,但这些项目在运行时不是动态的,则switch语句可能更适合。
HashSet<T>
。 - ChaosPandion为什么需要另一种方式?既然这不是功能问题,我猜测重点在于提高可读性。
如果您有一些具有有意义的名称的变量,那么使用 ==
进行比较会更易读。如果您有更多的变量,可以像其他示例中一样使用 Contains
对列表进行比较。
另一种方法是与枚举标志进行比较:
[Flags]
public enum Size
{
Small = 1,
Medium = 2,
Large = 4
}
接下来要找出mySize
是否属于Small
或Medium
:
selectedSizes = Size.Small | Size.Medium;
mySize = Size.Small;
if (mySize & selectedSizes)
{
...
}
试试这个
var res2 = new[] { 1, 2, 3 }.Any(x => x == 2);
if(a==x?true:a==y?true:a==z?true:false)
a
,这样你只需要计算一次。同时想象一下它被用在一个 lambda 内部,在那里你不想引入变量,因为 lambda 的单行语法更加简洁。在这种情况下第一个版本不能使用,如果你问我,第二个版本只会让人眼花缭乱。 - David Hedlund