ブール式でnull条件演算子を使用する最適な方法


11

次のようなブール式を書いています。

team.Category == "A Team" && team?.Manager?.IsVietnamVet

public class Manager
{
    public bool IsVietnamVet { get; set; }
}

public class Team
{
    public string Category { get; set; }

    public Manager Manager { get; set; }
}

...そしてエラーが発生します:

演算子 '&&'は、タイプ 'bool'および 'bool?'のオペランドには適用できません。

それを処理するための最適/クリーンな方法は何ですか?

  1. team.Category == "A Team" && (team?.Manager?.IsVietnamVet ?? false)

    それは本当に読みやすいですか?

  2. team.Category == "A Team" && (team?.Manager?.IsVietnamVet).GetValueOrDefault()

    LINQ-to-Entitiesでは機能しない可能性があります...

  3. team.Category == "A Team" && team?.Manager?.IsVietnamVet == true

    本当にif (condition == true)迷わず書いてみませんか?

他のオプションはありますか?最終的には次のように記述した方がよいですか。

  1. team.Category == "A Team" && team.Manager != null && team.Manager.IsVietnamVet

if(!(String.IsNullOrEmpty(team.Manager)&& condition))...
スヌープ

1
@StevieVそれは最初からこのようであることがメンでした;)
Santhos

1
コードをより注意深く見ると、null条件付き部分はになるはずですteam.Manager?.IsVietnamVet。つまり、null条件付き後teamはありませんnull
2016年

2
「もしも​​(条件== true)ためらわずに書いてくれませんか?」通常のブール値では不要です。ただし、null許容のbooleanの場合、これは重要です。nullableBool == true基本的にテスト中ですnullableBool != false && nullableBool != null(そして、この2番目の部分が有用であり、したがって不必要ではありません)
Flater

2
nullableBool == trueラッパーを作らないので使い始めました。== true@Flaterが言及しているように、通常のブール値を使用するときには通常は書き込みを行わないため、それは読み取り可能であり、変数はnull可能であることが示唆されています。さらに、@ Fabioが言及するように複数のnull条件を使用しないため、LINQの可読性が向上します。
Santhos

回答:


4

この特定のケースでは、それが従うのが賢明かもしれませんデメテルの法則すなわち

public class Team
{
    public bool IsManagerVietnamVet => Manager?.IsVietnamVet ?? false;
}    

より一般的には、ブール式が複雑または醜い場合、その式(またはその一部)を個別のステートメントに分割できなかったと言っても何もありません。

bool isVietnamVet = Manager?.IsVietnamVet ?? false;

if (team.Category == "A Team" && isVietnamVet)

デバッガーでコードをステップ実行するときbool、マウスオーバーによるホバリングを少し節約するためだけに、複雑な条件を1つにパッケージ化した方が良い場合がよくあります。実際、すべてをbool変数に入れる方が良いかもしれません。

bool isVietnamVetAndCategoryA = (team.Category == "A Team"
    && Manager?.IsVietnamVet ?? false);

if (isVietnamVetAndCategoryA)

またはLINQで:

var wibble = from flight in airport
             from passenger in flight.manifest
             let isOnPlane = 
                 (flight.FinishedBoarding && passenger.Flight == flight.FlightNumber)
             where !isOnPlane
             select passenger;

私は主にそのような解決策に傾いていると思います。
サントス2016年

1
数行を保存するための新しいC#構文:public bool IsManagerVietnamVet =>(team.Category == "")&&(team.Manager?.IsVietnamVet ?? false);
グラハム

long a && b && c &&...は順番に実行され、前のものが実行されても次のものが実行されないことを覚えておいてfalseください。したがって、人々は通常、最初に最速を置きます。物を別のブール
変数

@jitbit保守性についてです。あなたが言及しているようなマイクロ最適化は一般に不要です-パフォーマンスが問題として識別され、プロファイリングがそのような変更を行うと顕著な影響があることを示していない限り、心配する価値はありません。
Ben Cottrell

@BenCottrell IsManagerVietnamVetプロパティがデータベースにチェックインする場合、「マイクロ」最適化と呼びます;)
jitbit

3

オプション3(つまり== true)は、a bool?trueであることをテストする最もクリーンな方法だと思います。

ほとんどのコードで x == trueは、と同じなので意味xがありませんが、ここでは当てはまりませんので、== true混乱することはないと思います。


1
null条件演算子を使用したい場合は、これがlinqセーフでもあるため、間違いなくこれが適切な方法だと思います。問題は、読みやすさが良いかどうかです。私の観点から、選択はopt 3とopt 4の間であり、読みやすさの理由から3から4を選択します。また、プログラマーの意図は少し明確に思われます。私は、Ben Cottrellの答えを正しいとマークしました。そのアプローチがもう少し好きだからです。2つの回答にマークを付けることができれば、そうします。
Santhos

1
@Santhos-re「プログラマーの意図は少し明確に思えます」。私見、これはプログラマーが初めてa?.b == true混乱するのを見る場合ですが、彼らがそれが何をしているのかを理解すると、それは非常に読みやすいイディオムになり!= null、複雑な式の真ん中でテストする必要があるよりもずっといいです。以下のための同じa?.b ?? false、それはあなたがタイプを扱った場合は、入力したものと一致するので、最も人気のあるソリューションとして注目を集めていると思われる、他のブールより[私はboolean型のために好きではないけれども。私にとって、それは自然に読まない; 私が好みます== true]。
ToolmakerSteve 2018年

3

ベンコットレルの答えを拡張すると、「ヌルオブジェクト」パターンはさらに役立ちます。

nullチーム/マネージャーを返す代わりに、抽出ITeamしてIManagerインターフェイスし、意味のある代替実装を返します。

public class NoManager : IManager
{
    public bool IsVietnamVet => false;
}

public class NoTeam : ITeam
{
    public bool ManagedByVietnamVet => false;

    public IManager Manager => new NoManager();
}

その後、突然あなたが行うことができます team.ManagedByVietnamVet安全に。

もちろん、これは上流のプロバイダーteamがnullセーフであることを前提としていますが、適切なテストを行うことで確認できます。


-4

私はあなたが使用できる簡単なクラスを書きました:

 public class MyBool 
    {
        public bool? Value { get; set; }

        public MyBool(bool b)
        {
            Value = b;
        }

        public MyBool(bool? b)
        {
            Value = b;
        }

        public static implicit operator bool(MyBool m)
        {
            return m?.Value ?? false;
        }

        public static implicit operator bool?(MyBool m)
        {
            return m?.Value;
        }

        public static implicit operator MyBool(bool m)
        {
            return new MyBool(m);
        }

        public static implicit operator MyBool(bool? m)
        {
            return new MyBool(m);
        }

        public override string ToString()
        {
            return Value.ToString();
        }
    }

もちろん、カスタムタイプを使用すると信頼できる場合。あなたは比較することができMyBool、両方でboolNullable<bool>


1
このサイトは、特定のコードを機能させる方法ではなく、ソフトウェア設計に関する質問のためのものです。このため、これが最良のソリューションであると思われる場合は、このようなクラスが最良のソリューションであると考える理由に焦点を当てる必要があります。それを実装するために必要な正確なコード。
Ixrec 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.