可空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 ,则将value
与null
( default(T)
)进行比较,否则,如果T
是value 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==""