7

C Sharpで、いくつかの条件の1つが真であるかどうかをチェックするifステートメントを設定するにはどうすればよいですか?条件の1つだけである必要があり、0または2つ以上が真の場合、ifは偽である必要があります。

4

6 に答える 6

9

ヘルパーメソッドを書くことができます。これには、短絡し、必要な数だけを正確に評価するという利点があります。

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;
}
于 2012-05-24T21:03:22.907 に答える
5
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)
{
}

JasonのメソッドシグネチャのLinq実装:

public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions)
{
  int passingConditions = conditions
    .Where(x => x())
    // .Take(2) //optimization
    .Count();
  return passingConditions == 1;
}
于 2012-05-24T21:04:48.117 に答える
5

ブール値をboolシーケンスに構成してから、LINQを適用できます。

bool[] conditions = new bool[] { cond1, cond2, cond3, cond4 };
bool singleTrue = conditions.Count(cond => cond) == 1;

たった2つのブール値の場合、排他的論理和またははるかに単純になります。

bool singleTrue = cond1 != cond2;

編集:オンデマンド評価短絡を実現するにはbool、シーケンスをシーケンスに昇格させる必要がありFunc<bool>ます(各要素は条件の評価をカプセル化する関数デリゲートです)。

IEnumerable<Func<bool>> conditions = // define sequence here
int firstTrue = conditions.IndexOf(cond => cond());
bool singleTrue = firstTrue != -1 && 
                  conditions.Skip(firstTrue + 1).All(cond => !cond());

上記のスニペットは、述語ベースのIndexOf演算子の存在を前提としています。これは、現在のバージョンのLINQでは使用できませんが、次のような拡張メソッドとして定義できます。

public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    int i = 0;

    foreach (T element in source)
    {
        if (predicate(element))
            return i;

        i++;
    }

    return -1;
}

テスト用のサンプルデータ(ブレークポイントはそれぞれに設定されるfalsetrue、評価に続く場合があります):

IEnumerable<Func<bool>> conditions = new Func<bool>[] 
{ 
    () => 
        false,
    () => 
        true,
    () => 
        false,
    () => 
        false,
};
于 2012-05-24T21:02:06.943 に答える
4

簡単にするために、実行中のカウントを維持することができます。

int totalTrue = 0;
if (A) totalTrue++;
if (B) totalTrue++;
if (C) totalTrue++;
...
return (1 == totalTrue);
于 2012-05-24T20:59:37.360 に答える
2

これでうまくいくと思います

 int i= 0;
 if ( (!A || ++i <= 1) && 
      (!B || ++i <= 1) && 
      (!C || ++i <= 1) && 
      ... && 
      (i == 1))

私がこれについて間違っていると思わなかった場合、これifはすぐに誤りになりますi > 1。がインクリメントされず、最後の条件に到達した場合i、以降はfalseになります。i == 0

于 2012-05-24T21:04:12.810 に答える
0

これらの回答のほとんどは機能し、「良好なパフォーマンス」を発揮します。しかし、最も簡単な答えは次のとおりです。

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

A / B / Cを複数回評価することになりますので、これは単純なブールがある場合にのみ実際に役立ちます。

于 2012-05-28T17:49:30.393 に答える