可空类型:在 c# 中检查空或零的更好方法

Posted

技术标签:

【中文标题】可空类型:在 c# 中检查空或零的更好方法【英文标题】:Nullable types: better way to check for null or zero in 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);

有没有更好的办法?

【问题讨论】:

【参考方案1】:

我喜欢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)”,它自然会读作“为空或零”【参考方案2】:

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

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

这个解决方案

不需要其他方法, 比所有其他选项都快,因为GetValueOrDefault is a single field read operation¹ 和 比((item.Rate ?? 0) == 0) 更容易阅读(不过这可能是个人喜好问题)。

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

【讨论】:

【参考方案3】:

使用泛型:

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)) 进行比较,否则,如果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/…【参考方案4】:

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

【讨论】:

【参考方案5】:

我同意使用 ??操作员。

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

【讨论】:

【参考方案6】:

有没有更好的方法?

好吧,如果您真的在寻找更好的方法,您可能可以在 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)

【讨论】:

我认为你是对的,在早期阶段消除空值是可行的方法 不完全是。有一个概念叫做“重构”。您可以将代码重构为更好的模式或更好的结构。您始终可以在以后的阶段消除可为空的值。【参考方案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】:

C#9 : 你可以写

if (item.Rate is null or 0)

【讨论】:

【参考方案9】:
public static bool nz(object obj)

    return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));

【讨论】:

反射是,小心这样的解决方案。我不反对反射,但我不希望它出现在像这样的“简单”函数中,它会让我措手不及。 这实际上检查为零吗? 其实没有。我相信 Activator.CreateInstance(obj.GetType()) 将为可为空的类型返回 null。 @configurator:当可空类型被装箱时,它们被装箱为底层结构,也就是说,这不会构造一个可以为空的空值,而是一个默认值不可为空的结构。 【参考方案10】:
class Item  
 bool IsNullOrZero getreturn ((this.Rate ?? 0) == 0);

【讨论】:

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

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

String.IsNullOrEmpty(str)

代替:

str==null || str==""

【讨论】:

问题与“0”而不是空字符串进行比较。【参考方案12】:

使用 C# 7.0 或更高版本,您可以使用 is 关键字将对象与如下模式匹配:(请参阅 is operator - C# reference | Microsoft)

if (item is  Rate: 0 or null )

  // Do something

【讨论】:

Eric Bole-Feysot 已经发布了这个答案或类似的答案【参考方案13】:

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

【讨论】:

以上是关于可空类型:在 c# 中检查空或零的更好方法的主要内容,如果未能解决你的问题,请参考以下文章

c#异常可空对象必须要有一个值怎么解决

.NET(C#) Nullable(可空类型)通过扩展方法传委托参数调用方法

可空类型:在c#中检查null或0的最佳方法

C#可空类型(Nullable)

c# 中的可空类型是啥?

C# 8中的可空引用类型