Nullable型:C#でNullまたはゼロをチェックする最良の方法
質問
私は多くの多くの場所で次のことを確認しているプロジェクトに取り組んでいます:
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);
}
もっと良い方法はありますか?
解決
if ((item.Rate ?? 0) == 0) { }
が好き
更新1:
次のような拡張メソッドを定義することもできます:
public static bool IsNullOrValue(this double? value, double valueToCheck)
{
return (value??valueToCheck) == valueToCheck;
}
次のように使用します:
if(item.IsNullOrValue(0)){}
//しかし、そこから多くを得ることはありません
他のヒント
ジェネリックの使用:
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
はnull
(default(T)
)と比較されます。それ以外の場合、value type
がdefault(t)
の場合、二重に、false
は0d、boolは'\0'
、charは<=>などです...
受け入れられた答えは非常に好きですが、完全を期すために、このオプションについても言及すべきだと思います:
if (item.Rate.GetValueOrDefault() == 0) { }
このソリューション
- 追加のメソッドは不要です
- GetValueOrDefaultは他のすべてのオプションよりも高速です。単一フィールドの読み取り操作 <!>#185;そして
-
((item.Rate ?? 0) == 0)
より読みやすい(ただし、これは好みの問題かもしれません)。
<!>#185;ただし、これらの種類のマイクロ最適化によって違いが生じる可能性は低いため、これが決定に影響することはありません。
これは、ジェネリックのみを使用したFreddy Riosの受け入れられた答えの単なる拡張です。
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));
}
注値型または構造体のいずれかを扱っているため、nullのdefault(T)をチェックする必要はありません!これは、T valueToCheckがnullでないと安全に想定できることも意味します。ここでTを覚えていますか? Nullable <!> lt; T <!> gt;の略記です。そのため、Nullable <!> lt; T <!> gt;に拡張機能を追加します。メソッドをint?、double?、boolで取得しますか?など。
例:
double? x = null;
x.IsNullOrDefault(); //true
int? y = 3;
y.IsNullOrDefault(); //false
bool? z = false;
z.IsNullOrDefault(); //true
??の使用に同意しますオペレーター。
文字列を扱う場合は、if(String.IsNullOrEmpty(myStr))を使用します
より良い方法はありますか?
まあ、本当にもっと良い方法を探しているなら、おそらくRateの上に抽象化の別のレイヤーを追加することができます。 これが、Nullable Design Patternを使用して思いついたものです。
using System; using System.Collections.Generic; namespace NullObjectPatternTest { public class Program { 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 item in items) Console.WriteLine("Item Price: {0:C}", item.GetPrice()); } } public abstract class ItemBase { public abstract Rate Rate { get; } public int GetPrice() { // There is NO need to check if Rate == 0 or Rate == null return 1 * Rate.Value; } } public class Item : ItemBase { private readonly Rate _Rate; public override Rate Rate { get { return _Rate; } } public Item(Rate rate) { _Rate = rate; } } public sealed class RateFactory { public static Rate Create(int? rateValue) { if (!rateValue || rateValue == 0) return new NullRate(); return new Rate(rateValue); } } public class Rate { public int Value { get; set; } public virtual bool HasValue { get { return (Value > 0); } } public Rate(int value) { Value = value; } } public class NullRate : Rate { public override bool HasValue { get { return false; } } public NullRate() : base(0) { } } }
コードサンプルは失敗します。 objがnullの場合、obj.ToString()はnull参照例外になります。プロセスを短縮して、ヘルパー関数の開始時にnull objをチェックします。あなたの実際の質問に関して、あなたがnullまたはゼロをチェックしているタイプは何ですか? Stringには素晴らしいIsNullOrEmpty関数がありますが、これは拡張メソッドを使用してintにIsNullOrZeroメソッドを実装するのに最適でしょうか?タイプ。
編集:「?」 INullable型の単なるコンパイラシュガーなので、おそらくINullableをparmとして使用し、jsutでnullと比較し(parm == null)、nullでない場合はゼロと比較できます。
public static bool nz(object obj)
{
return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));
}
class Item{
bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
}
忘れないでください、文字列にはいつでも使用できます:
String.IsNullOrEmpty(str)
代わりに:
str==null || str==""
ジョシュアシャノンの優れた回答。 boxing / unboxing :
public static class NullableEx
{
public static bool IsNullOrDefault<T>(this T? value)
where T : struct
{
return EqualityComparer<T>.Default.Equals(value.GetValueOrDefault(), default(T));
}
}