【问题标题】:Nullable types: better way to check for null or zero in c#可空类型:在 c# 中检查空或零的更好方法
【发布时间】:2010-10-12 14:36:06
【问题描述】:

我正在做一个项目,我发现我在很多很多地方检查以下内容:

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

有没有更好的办法?

【问题讨论】:

    标签: c# null zero


    【解决方案1】:

    C#9 : 你可以写

    if (item.Rate is null or 0)
    

    【讨论】:

      【解决方案2】:

      Joshua Shannon 的漂亮answer 更进一步。现在防止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));
          }
      }
      

      【讨论】:

        【解决方案3】:

        别忘了,对于字符串,你总是可以使用:

        String.IsNullOrEmpty(str)
        

        代替:

        str==null || str==""
        

        【讨论】:

        • 问题与“0”而不是空字符串进行比较。
        【解决方案4】:

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

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

        这个解决方案


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

        【讨论】:

          【解决方案5】:

          我喜欢if ((item.Rate ?? 0) == 0) { }

          更新 1:

          您还可以定义一个扩展方法,例如:

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

          并像这样使用它:

          if(item.IsNullOrValue(0)){} // 但你并没有从中得到什么

          【讨论】:

          • 谢谢 - 非常简洁!我担心可读性,但得出的结论是,如果我真正理解了 ??运算符。
          • 你应该使用扩展方法;虽然在编写时它是可读的,但这个小代码块需要一点点思考,这意味着如果你尝试阅读代码并使用它 - 你会从主要问题上分心。
          • @nailitdown:不是真的,你只需要一个 Nullable 的扩展方法。双倍的?是 Nullable 的别名。您的签名将如下所示: public static bool IsNullOrValue(this Nullable, t valueToCheck) where T : struct
          • @nailitdown:(第二部分)您的 return 语句看起来像 return (value ?? default(T)).Equals(valueToCheck);
          • 如果将其缩短为“IsNullOr(0)”,它自然会读作“为空或零”
          【解决方案6】:

          这实际上只是 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));
          }
          

          注意我们不需要检查 default(T) 是否为 null,因为我们正在处理值类型或结构!这也意味着我们可以安全地假设 T valueToCheck 不会为空;记得这里那个T吗?是 Nullable 的简写,所以通过向 Nullable 添加扩展,我们可以在 int?, double?, bool?等等

          示例:

          double? x = null;
          x.IsNullOrDefault(); //true
          
          int? y = 3;
          y.IsNullOrDefault(); //false
          
          bool? z = false;
          z.IsNullOrDefault(); //true
          

          【讨论】:

            【解决方案7】:

            您的代码示例将失败。如果 obj 为 null,则 obj.ToString() 将导致 null 引用异常。我会缩短该过程并在您的辅助函数开始时检查 null obj。至于您的实际问题,您要检查的类型是 null 还是零?在 String 上有一个很棒的 IsNullOrEmpty 函数,在我看来这将是一个很好的使用扩展方法来在 int 上实现 IsNullOrZero 方法?输入。

            编辑:记住,“?”只是 INullable 类型的编译器糖,因此您可能将 INullable 作为参数,然后将其与 null (parm == null) 进行比较,如果不是 null,则与零进行比较。

            【讨论】:

            • 为捕获该错误而欢呼 - 在这个项目中,我需要检查 int?、double?、decimal? 等,这就是我使用“object”的原因
            • 记住,'?'只是 INullable 类型的编译器糖,因此您可以将 INullable 作为参数,然后将其与 null (parm == null) 进行比较,如果不为 null,则与零进行比较。
            【解决方案8】:

            有没有更好的方法?

            好吧,如果您真的在寻找更好的方法,您可能可以在 Rate 之上添加另一层抽象。 好吧,这是我刚刚想出的使用 Nullable 设计模式。

            使用系统; 使用 System.Collections.Generic; 命名空间 NullObjectPatternTest { 公开课程序 { 公共静态无效主要(字符串[]参数) { var items = 新列表 { 新项目(RateFactory.Create(20)), 新项目(RateFactory.Create(空)) }; PrintPricesForItems(项目); } 私有静态无效 PrintPricesForItems(IEnumerable 项目) { foreach (var item in items) Console.WriteLine("商品价格:{0:C}", item.GetPrice()); } } 公共抽象类 ItemBase { 公共抽象费率{得到; } 公共 int GetPrice() { // 无需检查 Rate == 0 或 Rate == null 返回 1 * Rate.Value; } } 公共类项目:ItemBase { 私有只读速率_Rate; 公共覆盖率率 { 得到 { 返回 _Rate; } } 公共项目(费率){ _Rate = 费率; } } 公共密封类 RateFactory { 公共静态速率创建(int?rateValue) { 如果 (!rateValue || rateValue == 0) 返回新的 NullRate(); 返回新的速率(rateValue); } } 公开课率 { 公共 int 值 { 获取;放; } public virtual bool HasValue { get { return (Value > 0); } } 公共利率(整数值){价值=价值; } } 公共类 NullRate : 率 { 公共覆盖 bool HasValue { get { return false; } } 公共 NullRate() : 基数(0) { } } }

            【讨论】:

            • 我认为你是对的,在早期阶段消除空值是可行的方法
            • 不完全是。有一个概念叫做“重构”。您可以将代码重构为更好的模式或更好的结构。您始终可以在以后的阶段消除可为空的值。
            【解决方案9】:

            使用泛型:

            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,假设是double , default(t) 是 0d,bool 是 false,char 是 '\0' 等等...

            【讨论】:

            • 扩展方法:public static bool IsNullOrValue&lt;T&gt;(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
            • 我喜欢这个解决方案的清洁度。请记住 default(int?)null 而不是 0 但是。所有可为空的值(整数)类型的默认值为 null,如果在此方法中传递 0,则将返回 false。见:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
            【解决方案10】:
            class Item{  
             bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
            }
            

            【讨论】:

            • 您的解决方案适用于一个属性,我应该指定我有许多相同项目的属性来检查空/零
            【解决方案11】:

            我同意使用 ??操作员。

            如果您正在处理字符串,请使用 if(String.IsNullOrEmpty(myStr))

            【讨论】:

              【解决方案12】:
              public static bool nz(object obj)
              {
                  return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));
              }
              

              【讨论】:

              • 反射是,小心这样的解决方案。我不反对反射,但我不希望它出现在像这样的“简单”函数中,它会让我措手不及。
              • 这实际上检查为零吗?
              • 其实,没有。我相信 Activator.CreateInstance(obj.GetType()) 将为可为空的类型返回 null。
              • @configurator:当可空类型被装箱时,它们被装箱为底层结构,也就是说,这不会构造一个可以为空的空值,而是一个默认值不可为空的结构。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-30
              • 1970-01-01
              • 2022-08-02
              • 2010-09-27
              • 2021-05-02
              相关资源
              最近更新 更多