null許容型:C#でnullまたはゼロをチェックするためのより良い方法


85

私は多くの場所で次のことをチェックしていることがわかったプロジェクトに取り組んでいます:

if(item.Rate == 0 || item.Rate == null) { }

何よりも好奇心として、両方のケースをチェックするための最良の方法は何ですか?

次のようなヘルパーメソッドを追加しました。

public static bool nz(object obj)
{
    var parsedInt = 0;
    var parsed = int.TryParse(obj.ToString(), out parsedInt);
    return IsNull(obj) || (parsed && parsedInt == 0);
}

もっと良い方法はありますか?

回答:


162

好き if ((item.Rate ?? 0) == 0) { }

アップデート1:

次のような拡張メソッドを定義することもできます。

public static bool IsNullOrValue(this double? value, double valueToCheck)
{
    return (value??valueToCheck) == valueToCheck;
}

そして、次のように使用します。

if(item.IsNullOrValue(0)){} //しかし、あなたはそれから多くを得ません


3
ありがとう-非常に簡潔です!私は読みやすさに関心がありましたが、実際に理解していれば完全に読みやすいという結論に達しました。オペレーター。
釘付け2009年

2
拡張メソッドを使用する必要があります。執筆時点では読み取り可能ですが、この小さなコードナゲットは、ほんの少しの思考を必要とします。つまり、コードを読み取ろうとしてそれを使用すると、主な問題に気を取られてしまいます。
コンフィギュレー

11
@nailitdown:そうではありませんが、Nullable <T>の拡張メソッドが必要です。ダブル?Nullable <double>のエイリアスです。署名は次のようになります。publicstaticboolIsNullOrValue <T>(this Nullable <T>、t valueToCheck)where T:struct
Joshua Shannon

3
@nailitdown :(パートII)returnステートメントはreturn(value ?? default(T))。Equals(valueToCheck);のようになります。
Joshua Shannon

2
これを「IsNullOr(0)」に短縮すると、当然「is null
orzero

41

ジェネリックの使用:

static bool IsNullOrDefault<T>(T value)
{
    return object.Equals(value, default(T));
}

//...
double d = 0;
IsNullOrDefault(d); // true
MyClass c = null;
IsNullOrDefault(c); // true

場合T、それはです参照型valueと比較されますnulldefault(T))、そうでない場合は、場合Tであるvalue type、のは、ダブル言わせて、default(t)ブール値のため、0Dですfalse、CHARのためである'\0'というように...


1
拡張方法:public static bool IsNullOrValue<T>(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
BehzadEbrahimi19年

39

私は受け入れられた答えがとても好きですが、完全を期すために、このオプションも言及されるべきだと思います:

if (item.Rate.GetValueOrDefault() == 0) { }

このソリューション


¹ただし、これらの種類のマイクロ最適化が違いを生む可能性は低いため、これが決定に影響を与えることはありません。


19

これは実際には、ジェネリックスのみを使用したフレディリオスの受け入れられた答えの単なる拡張です。

public static bool IsNullOrDefault<T>(this Nullable<T> value) where T : struct
{
    return default(T).Equals( value.GetValueOrDefault() );
}

public static bool IsValue<T>(this Nullable<T> value, T valueToCheck) where T : struct
{
    return valueToCheck.Equals((value ?? valueToCheck));
}

NOTE我々は値の型や構造体のいずれかを扱っているので、私たちがnullのデフォルト(T)をチェックする必要はありません!これは、TvalueToCheckがnullにならないことを安全に想定できることも意味します。ここでそのTを覚えていますか?はNullable <T>の省略形なので、Nullable <T>に拡張機能を追加することで、int?、double?、bool?のメソッドを取得します。等

例:

double? x = null;
x.IsNullOrDefault(); //true

int? y = 3;
y.IsNullOrDefault(); //false

bool? z = false;
z.IsNullOrDefault(); //true

2

??の使用に同意します オペレーター。

文字列を扱っている場合は、if(String.IsNullOrEmpty(myStr))を使用します


2

もっと良い方法はありますか?

まあ、あなたが本当により良い方法を探しているなら、あなたはおそらくレートの上に抽象化の別の層を追加することができます。これが、Nullable DesignPatternを使用して思いついたものです。

システムを使用する;
System.Collections.Genericを使用する;

名前空間NullObjectPatternTest
{{
    パブリッククラスプログラム
    {{
        public static void Main(string [] args)
        {{
            var items = new List
                            {{
                                new Item(RateFactory.Create(20))、
                                new Item(RateFactory.Create(null))
                            };

            PrintPricesForItems(items);
        }

        private static void PrintPricesForItems(IEnumerable items)
        {{
            foreach(アイテム内のvarアイテム)
                Console.WriteLine( "アイテム価格:{0:C}"、item.GetPrice());
        }
    }

    パブリック抽象クラスItemBase
    {{
        public abstract Rate Rate {get; }
        public int GetPrice()
        {{
            //レート== 0またはレート== nullかどうかを確認する必要はありません
            1 * Rate.Valueを返します。
        }
    }

    パブリッククラスItem:ItemBase
    {{
        プライベート読み取り専用Rate_Rate;
        public override Rate Rate {get {return _Rate; }}
        public Item(Rate rate){_ Rate = rate; }
    }

    パブリックシールクラスRateFactory
    {{
        public static Rate Create(int?rateValue)
        {{
            if(!rateValue || rateValue == 0) 
                新しいNullRate();を返します。
            新しいRate(rateValue);を返します。
        }
    }

    パブリッククラスレート
    {{
        public int Value {get; セットする; }
        public virtual bool HasValue {get {return(Value> 0); }}
        public Rate(int value){値=値; }
    }

    パブリッククラスNullRate:レート
    {{
        public override bool HasValue {get {return false; }}
        public NullRate():base(0){}
    }
}

1
早い段階でnull値を削除することが道のりだったと思いますが、
釘付け

ではない正確に。「リファクタリング」という概念があります。より良いパターンまたはより良い構造に向けてコードをリファクタリングできます。後の段階でnull許容値をいつでも削除できます。
dance2die 2009年

2

コードサンプルは失敗します。objがnullの場合、obj.ToString()はnull参照例外になります。プロセスをショートカットして、ヘルパー関数の開始時にnullobjをチェックします。あなたの実際の質問に関して、あなたがヌルまたはゼロをチェックしているタイプは何ですか?Stringには素晴らしいIsNullOrEmpty関数がありますが、これは拡張メソッドを使用してintにIsNullOrZeroメソッドを実装するのに最適だと思いますか?タイプ。

編集:覚えておいてください、「?」はINullable型の単なるコンパイラシュガーであるため、おそらくINullableをparmとして取得し、それをnull(parm == null)と比較し、nullでない場合はゼロと比較することができます。


そのバグをキャッチするための歓声-このプロジェクトでは、int?、double?、decimal?などをチェックする必要があります。そのため、「オブジェクト」を使用しています
釘付け2009年

覚えておいてください、「?」はINullable <T>型の単なるコンパイラシュガーであるため、おそらくINullable <T>をparmとして取得し、それをnull(parm == null)と比較し、nullでない場合はゼロと比較します。
Walden Leverich

0
public static bool nz(object obj)
{
    return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));
}

1
反射が遅いので、このような解決策には注意してください。私は反省に反対しませんが、このような「単純な」機能でそれを期待することはなく、それは私を不意を突かせるでしょう。
Walden Leverich

これは実際にゼロをチェックしますか?
釘付け2009年

実は違う。Activator.CreateInstance(obj.GetType())は、null許容型に対してnullを返すと思います。
コンフィギュレー

@configurator:null許容型がボックス化されている場合、それらは基になる構造体としてボックス化されます。つまり、これはnull値nullableではなく、デフォルト値のnull不可能な構造体を構築します。
Eamon Nerbonne 2010年

0
class Item{  
 bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
}

あなたのソリューションは1つのプロパティで機能します
。null

0

文字列の場合は、いつでも次のものを使用できることを忘れないでください。

String.IsNullOrEmpty(str)

の代わりに:

str==null || str==""

1
質問は、空の文字列ではなく「0」と比較されます。
dance2die 2009年

-1

JoshuaShannonのいい答えからさらに一歩。今ボクシング/開封を防ぐことで:

public static class NullableEx
{
    public static bool IsNullOrDefault<T>(this T? value)
        where T : struct
    {
        return EqualityComparer<T>.Default.Equals(value.GetValueOrDefault(), default(T));
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.