C# 如果语句-';或';但不是';和';

C# 如果语句-';或';但不是';和';,c#,if-statement,C#,If Statement,在C语言中,如何设置一个if语句来检查几个条件中的一个是否为真?它只能是其中一个条件,如果零或两个或多个条件为真,则if应为假。为了简单起见,您可以保留一个运行计数: int totalTrue = 0; if (A) totalTrue++; if (B) totalTrue++; if (C) totalTrue++; ... return (1 == totalTrue); 您可以使用将布尔值组合成bool序列,然后应用LINQ: bool[] conditions = new bool

在C语言中,如何设置一个if语句来检查几个条件中的一个是否为真?它只能是其中一个条件,如果零或两个或多个条件为真,则if应为假。

为了简单起见,您可以保留一个运行计数:

int totalTrue = 0;
if (A) totalTrue++;
if (B) totalTrue++;
if (C) totalTrue++;
...
return (1 == totalTrue);

您可以使用将布尔值组合成
bool
序列,然后应用LINQ:

bool[] conditions = new bool[] { cond1, cond2, cond3, cond4 };
bool singleTrue = conditions.Count(cond => cond) == 1;
对于两个布尔人来说,独占or变得简单得多:

bool singleTrue = cond1 != cond2;
编辑:为了实现按需评估和短路,我们需要将
bool
序列升级为
Func
序列(其中每个元素都是封装条件评估的函数委托):

测试的样本数据(可在每个
false
true
上设置断点,以进行评估):

IEnumerable conditions=new Func[]
{ 
() => 
假,,
() => 
是的,
() => 
假,,
() => 
假,,
};

您可以编写一个助手方法。这样做的好处是它会短路,只需根据需要准确评估

public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions) {
    bool any = false;
    foreach (var condition in conditions) {
        bool result = condition();
        if (any && result) {
            return false;
        }
        any = any | result;
    }
    return any;
}
公共静态bool IsExactlyOneTrue(IEnumerable条件){
bool any=false;
foreach(条件中的var条件){
bool结果=条件();
如果(任何&&结果){
返回false;
}
any=任何|结果;
}
退回任何文件;
}

我想这就可以了

 int i= 0;
 if ( (!A || ++i <= 1) && 
      (!B || ++i <= 1) && 
      (!C || ++i <= 1) && 
      ... && 
      (i == 1))
inti=0;
如果(!A | |++i
List criteria=new List();
添加(c=>c.Name.StartsWith(“B”);
添加(c=>c.Job==Jobs.Plumber);
添加(c=>c.IsExcellent);
Customer myCustomer=GetCustomer();
int criteriaCount=标准
.其中(q=>q(我的客户))
//.Take(2)//优化
.Count()
如果(标准计数==1)
{
}

Jason方法签名的Linq实现:

public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions)
{
  int passingConditions = conditions
    .Where(x => x())
    // .Take(2) //optimization
    .Count();
  return passingConditions == 1;
}
公共静态bool IsExactlyOneTrue(IEnumerable条件)
{
int passingConditions=条件
.其中(x=>x())
//.Take(2)//优化
.Count();
返回传递条件==1;
}

这些答案中的大多数都是有效的,并且具有“良好的性能”。但最简单的答案是:

if( (A & !(B || C)) || 
    (B & !(A || C)) ||
    (C & !(A || B)) )
{
   ...
}


你会不止一次地计算A/B/C,所以这只有在你有简单的布尔值时才有用。

这有一个缺点,那就是必须计算所有的条件。这可以通过将其更改为A
Func[]
并使用
条件来解决。其中(cond=>cond()).Skip(1)。Any();
@TimS.:不会
Skip(1)
当所有值都为false时失败?嗯…它不会像抛出时那样“失败”,但它的行为不太正确-它返回true。我在对Jason的答案的评论中发布了一个修订。回答很好。也可以在与特定类型无关的情况下执行:
var conditions=new List();conditions.Add(()=>foo==bar);如果(conditions.Select(x=>x.Invoke()).Count(x=>x)==1){}
当然,您只是将特定实例推到criteria中。我的“criteria”收集延迟了拥有一个适用实例的需要,并且可以重复使用尽可能多的实例。这种方法需要评估所有条件,无论是否必要。我更喜欢允许短路的方法。不。只需取消注释Take,执行就会在第一时间停止。@David B:the
Take现在没有取消注释,是吗?此方法可以简化为
return!条件。其中(cond=>cond()).Skip(1).Any()
它的可读性更高,运行速度可能会慢一些,但除非发现这一点非常重要,否则我会选择更简洁的。进一步看,这必须更像这样才能正常工作:
var trueConditions=conditions.Where(cond=>cond());if(!trueConditions.Take(1).Any())return false;return!trueConditions.Skip(1).Any();
我开始比我的LINQ方法更喜欢你的答案了。@TimS::但这可能会导致前面的假结果表达式被计算两次。我认为在LINQ中没有任何优雅的方法可以做到这一点(除非通过预测指数,否则无法达到全部目的).确实如此。我只是用一个假表达式测试了它,然后用一个真表达式测试了它,每个表达式计算了两次。它可能是可以修复的,但它的复杂性越来越大,远远超过了Jason的解决方案。LINQ只是不能很好地处理这种情况。@TimS.:我做了更多的实验,发现如果假设存在,它可以在LINQ中优雅地完成基于谓词的
IndexOf
运算符的tence(易于定义)请看下面我的编辑答案。我个人将最后一个语句写为<代码>返回ToalTrime= 1;。我了解向后写这些测试的理由,但我不同意它,括号是不必要的。@ Keththoppson,我只想让自己习惯于按顺序写代码,以防我回到C++。Adam V:在罗马,做罗马人的事。C和C++不是同一种语言。不要在C++中写C语言,在C语言中不要用C++。杰森:如果是无效的代码,或者在语言之间改变了意思的代码,我同意你的看法。但是,因为它只是一种习惯,我会保留它。Adam V:这是事实。当C程序员读C代码时,他们期望看到C。在C#中输入。语言中有一些习语,与这些习语相反的代码会让人分心。@Tim S。在其他几个不同答案的评论中输入你的答案是很不礼貌的。删除这些评论,将你的答案作为答案发布,并接受投票的判断——正如Jeff所想的那样。
 int i= 0;
 if ( (!A || ++i <= 1) && 
      (!B || ++i <= 1) && 
      (!C || ++i <= 1) && 
      ... && 
      (i == 1))
List<Func<Customer, bool>> criteria = new List<Func<Customer, bool>>();

criteria.Add(c => c.Name.StartsWith("B"));
criteria.Add(c => c.Job == Jobs.Plumber);
criteria.Add(c => c.IsExcellent);

Customer myCustomer = GetCustomer();

int criteriaCount = criteria
  .Where(q => q(myCustomer))
  // .Take(2)  // optimization
  .Count()
if (criteriaCount == 1)
{
}
public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions)
{
  int passingConditions = conditions
    .Where(x => x())
    // .Take(2) //optimization
    .Count();
  return passingConditions == 1;
}
if( (A & !(B || C)) || 
    (B & !(A || C)) ||
    (C & !(A || B)) )
{
   ...
}