仅当一个参数为真时,运算符才返回真。

3

我正在使用C#编写一个if语句,如果仅有一个参数为true,我希望它返回true。在示例中,我将使用||,因为这是我能想到的最接近的东西:

int a = 1;
int b = 2;
int c = 3;

if(a == 1 || b == 2)
{
Console.Log("The first statement is true")
}

if(a == 1 || b == 3)
{
Console.Log("The second statement is true")
}

if(a == 0 || b == 0 || c == 3)
{
Console.Log("The third statement is true")
}

if(a == 1 || b == 0 || c == 3)
{
Console.Log("The fourth statement is true")
}

//Output:
//The second statement is true
//The third statement is true

再次思考一下||作为我正在寻找的运算符。是否存在这样一个运算符,还是我应该定义自己的布尔函数?


请注意,在所有这些比较中,您需要使用==而不是=。将伪代码尽可能地写得逼真有助于您的编程。 - Jon Skeet
@JonSkeet 我完全忘记了。我习惯于代码下面有一条大红线告诉我它是错误的...哈哈。现在会修复。 - Tanner Fix-It Smith
3个回答

12

对于两个表达式,您可以使用 XOR 运算符:

if (a == 1 ^ b == 0)

如果超过两个,你可以这样做:

if (new[] { a == 1, b == 0, c == 2 }.Count(x => x) == 1)

基本上这会将由表达式构成的数组中所有"true"元素计数,并检查计数是否为1。

诚然,这会首先评估所有条件,即使前两个是true(因此最后一个无关紧要),也会计算它们。如果这对你来说太昂贵了,那么还有更复杂的替代方案,但除非实际存在问题,否则我肯定会坚持使用类似这样的方法。


3
我认为 x ^ y ^ z 可以解决问题,但如果这三个都是 true,它会错误地返回 true。似乎以下方法更正确。 - p.s.w.g
这看起来很有道理。我会实现它,并在这里回复您,如果我有其他问题。真让我惊讶的是,像我在原帖中描述的这样的运算符竟然不存在。 - Tanner Fix-It Smith
@TannerFix-ItSmith:为什么你会感到惊讶呢?我不记得每个人都想要这样的东西...而且在具有可变数量参数的运算符方面,这将是奇怪的。 - Jon Skeet
@JonSkeet 我尝试了一下,但是它抛出了一个错误。显然 bool[] 没有 .Count() 方法? - Tanner Fix-It Smith
@TannerFix-ItSmith:你需要在代码顶部添加一个using指令来引用System.Linq,即using System.Linq; - Jon Skeet
@JonSkeet 好吧,我假设在像我的示例中的if语句中:if(a == 1 ^ b == 0 ^ c == 3)它会执行以下操作:1)将a == 1评估为true。2)用true替换a == 1,以便该行将被读作if(true ^ b == 0 ^ c == 3)3)将b == 0评估为false。4)在代码中用false替换b == 0,以便该行将被读作if(true ^ false ^ c == 3)5)将true ^ false评估为true。...然后,当我打这个时,我意识到这是什么意思。算了,哈哈。 - Tanner Fix-It Smith

0

没有这样的运算符。但是你可以尝试这个:

var statements = new[] { a == 0, b == 2, c == 2 };
switch (statements.Count(x => x))
{
    case 0: Console.WriteLine("None of statement is true"); break;
    case 1:
        Console.WriteLine("The {0} statement is true", 
            new[] { "first", "second", "third" }.Skip(statements.TakeWhile(x => !x).Count()).First());
        break;

    default:
        Console.WriteLine("More than one statement is true");
        break;
}

输出:

第二个语句是正确的


这并不仅检查一个表达式是否为真。 - Jon Skeet
@JonSkeet 已修复。 - Xiaoy312
1
我认为 OP 不需要知道哪个条件是真的,尽管我可能错了...(请注意,在示例中,每个 if 语句中的条件都不同。) - Jon Skeet
@JonSkeet 你说的“I don't think”是什么意思?我正在使用Unity编写一个游戏,并需要检查当前帧是否只有三个按钮中的一个被按下,可使用bool Input.GetButton(string name)来实现。 - Tanner Fix-It Smith
@TannerFix-ItSmith 顺便说一下,既然你在使用它,你可以很好地将验证与new [] { "buttonX", "buttonY", "buttonZ" }.Count(Input.GetButton) == 1链接起来。 - Xiaoy312
显示剩余2条评论

0

对于2个操作数,XOR(^)运算符可以实现此功能。来自MSDN

对于bool操作数,^计算其操作数的逻辑异或;也就是说,仅当其操作数中恰好有一个为true时,结果才为true

对于三个或更多操作数,Jon is correct,您只需要循环遍历条件即可。但是,如果要检查的条件非常多(或者只有一些非常昂贵的条件),则可能通过在找到第二个true时短路结果来实现性能提升,如下所示:

var conditions = ...
if (conditions.Where(x => x).Take(2).Count() == 1) 

或者如果您更喜欢一些不那么神秘的东西,也许可以使用扩展方法

public static bool ExactlyOne(this IEnumerable<T> source, Func<T, bool> predicate)
{
    var found = false;
    foreach(var x in source)
    {
        var result = predicate(x);
        if (result && found) {
            return false;
        }
        found = result;
    }

    return found;
}

var conditions = ...
if (conditions.ExactlyOne(x => x)) 

但是,对于多个条件,这种方法不能得到OP想要的结果。例如,true ^ true ^ false ^ true计算结果为true - hatchet - done with SOverflow
是的,我也想提出同样的问题。我需要像这样在每个操作数对之间加括号吗:if ((a == x ^ b == y) ^ c == z),还是可以不用括号写它们? - Tanner Fix-It Smith
@JonSkeet 纠正并添加了“短路”解决方案,这样我的答案就不会完全与你的答案无关了:P - p.s.w.g

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接