可空types:在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)){}但你没有从它得到很多

使用generics:

 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引用types ,则将valuenulldefault(T) )进行比较,否则,如果Tvalue type ,比如说double,则default(t)为0d,因为bool为false'\0'等等…

虽然我非常喜欢接受的答案,但我认为,为了完整起见,还应该提及这个选项:

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

这个解决scheme

  • 不需要额外的方法,
  • 比所有其他选项快,因为GetValueOrDefault是一个单独的字段读操作 ¹和
  • 读取比((item.Rate ?? 0) == 0)更容易(但这可能是一个口味问题)。

¹但这不应该影响您的决定,因为这种微观优化不太可能会产生任何影响。

这实际上只是弗雷迪·里奥斯(Freddy Rios)接受的使用generics(Generics)的答案。

 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)); } 

注意我们不需要检查默认(T)为null,因为我们正在处理值types或结构体! 这也意味着我们可以安全地假设T值ToCheck不会为空; 还记得那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 

我同意使用?? 运营商。

如果你正在处理string,使用if(String.IsNullOrEmpty(myStr))

你的代码示例将失败。 如果obj为null,那么obj.ToString()将导致空引用exception。 我会简化这个过程,并在你的帮助函数开始时检查一个null obj。 至于你的实际问题,你检查null或零的types是什么? 在string有一个伟大的IsNullOrEmpty函数,在我看来这将是一个很好的扩展方法来实现一个IsNullOrZero方法的int? types。

编辑:请记住,'?' 只是INullabletypes的编译器糖,所以你可以把一个INullable作为PARM,然后将其与null(parm == null)进行比较,如果不为零,则比较为零。

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

有没有更好的办法?

那么,如果你真的想找一个更好的方法,那么你可以在速率的基础上增加一个抽象层。 那么这里是我刚刚使用可空devise模式的东西。

使用系统;
使用System.Collections.Generic;

命名空间NullObjectPatternTest
 {
    公共课程
     {
         public static void Main(string [] args)
         {
             var items =新列表
                             {
                                新项目(RateFactory.Create(20)),
                                新项目(RateFactory.Create(null))
                             };

             PrintPricesForItems(项目);
         }

        私人静态无效的PrintPricesForItems(IEnumerable项目)
         {
             foreach(项目中的var项目)
                 Console.WriteLine(“Item Price:{0:C}”,item.GetPrice());
         }
     }

    公共抽象类ItemBase
     {
         public abstract Rate Rate {get;  }
         public int GetPrice()
         {
             //不需要检查Rate == 0或Rate == null
            返回1 * Rate.Value;
         }
     }

    公共类Item:ItemBase
     {
        私人只读率_Rate;
        公众覆盖率Rate {get {return _Rate;  }}
         public Item(Rate rate){_Rate = rate;  }
     }

    公开密封的RateFactory类
     {
        公共静态费率创build(int?rateValue)
         {
             if(!rateValue || rateValue == 0) 
                返回新的NullRate();
            返回新的费率(rateValue);
         }
     }

    公开课率
     {
         public int Value {get; 组;  }
        公共虚拟布尔HasValue {得到{返回(值> 0);  }}
         public Rate(int value){Value = value;  }
     }

     public class NullRate:Rate
     {
        公共覆盖布尔值HasValue {获得{返回false;  }}
         public NullRate():base(0){}
     }
 }
 class Item{ bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}} } 

不要忘记,对于string,你总是可以使用:

 String.IsNullOrEmpty(str) 

代替:

 str==null || str==""