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


85

我正在一个项目中工作,我发现我正在许多地方检查以下各项:

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

有没有更好的办法?

Answers:


161

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

更新1:

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

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

并像这样使用它:

if(item.IsNullOrValue(0)){} //但是您从中得到的并不多


3
谢谢-非常简洁!我关心的是可读性,但得出的结论是,如果我真正理解??,它将完全可读。操作员。
nailitdown

2
您应该使用扩展方法;尽管在编写本文时可读性强,但是这个小小的代码块需要一些思考,这意味着如果您尝试阅读代码并使用它,那么您就可以摆脱主要问题的困扰。
配置器

11
@nailitdown:不是,您只需要Nullable <T>的扩展方法。双?是Nullable <double>的别名。您的签名将如下所示:public static bool IsNullOrValue <T>(this Nullable <T>,t valueToCheck)其中T:struct
Joshua Shannon,2009年

3
@nailitdown :(第二部分)然后,您的return语句将看起来像return(value ?? default(T))。Equals(valueToCheck);
约书亚·香农

2
如果将其缩短为“ IsNullOr(0)”,它自然会读作“为null或零”
ChrisFox

41

使用泛型:

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是a value type,比如说double,default(t)是0d,对于bool是false,对于char是'\0',依此类推...


1
扩展方法:public static bool IsNullOrValue<T>(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
Behzad Ebrahimi

39

尽管我非常喜欢已接受的答案,但我认为为了完整起见,还应该提到此选项:

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

这个解决方案


¹不过,这不会影响您的决定,因为这类微优化不太可能产生任何变化。


19

这实际上只是Freddy Rios仅使用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));
}

注意,由于我们正在处理值类型或结构,因此无需检查default(T)是否为空!这也意味着我们可以安全地假定T valueToCheck将不为null;还记得这里的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


2

有没有更好的办法?

好吧,如果您确实在寻找更好的方法,则可以在Rate之上添加另一层抽象。好吧,这是我刚刚使用Nullable Design Pattern想到的。

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

命名空间NullObjectPatternTest
{
    公共课程
    {
        公共静态无效的Main(string [] args)
        {
            var项目=新列表
                            {
                                新Item(RateFactory.Create(20))
                                新项目(RateFactory.Create(null))
                            };

            PrintPricesForItems(items);
        }

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

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

    公共类Item:ItemBase
    {
        私有只读Rate _Rate;
        公共优先级Rate Rate {get {return _Rate; }}
        公共项目(费率){_Rate =费率;}
    }

    公共密封类RateFactory
    {
        公共静态Rate Create(int?rateValue)
        {
            如果(!rateValue || rateValue == 0) 
                返回新的NullRate();
            返回新的Rate(rateValue);
        }
    }

    公开课费率
    {
        public int Value {get; 组; }
        公共虚拟布尔HasValue {get {return(Value> 0); }}
        public Rate(int value){Value = value; }
    }

    公共类NullRate:费率
    {
        公开覆盖bool HasValue {get {return false; }}
        公共NullRate():基数(0){}
    }
}

1
我认为你是正确的,消除了一些前期空值会一直要走的路
nailitdown

不完全是。有一个称为“重构”的概念。您可以将代码重构为更好的模式或更好的结构。您始终可以在以后的阶段消除可为空的值。
dance2die

2

您的代码示例将失败。如果obj为null,则obj.ToString()将导致null引用异常。我将简化该过程,并在辅助函数的开头检查是否为空obj。至于您的实际问题,您要检查的是null还是0的类型是什么?在String上有一个很棒的IsNullOrEmpty函数,在我看来,这将是扩展方法在int上实现IsNullOrZero方法的很好用吗?类型。

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


为捕获该错误而欢呼-在此项目中,我需要检查int?,double?,decimal?等。这就是为什么我使用“ object”的原因
nailitdown 2009年

记住,“?” 只是INullable <T>类型的编译器糖,因此您可能将INullable <T>作为参数,然后jsut将其与null比较(parm == null),如果不为null,则比较为零。
Walden Leverich 2009年

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

1
反射缓慢,请谨慎使用此类解决方案。我不反对反射,但是我不希望这样的“简单”函数会反射它,这会使我措手不及。
Walden Leverich'2009年

这实际上检查零吗?
nailitdown

其实没有 我相信Activator.CreateInstance(obj.GetType())对于可为空的类型将返回null。
配置器

@configurator:将可空类型装箱后,将它们装箱为基础结构,即,因此,这将不会构造可空值的空值,而将构造默认值的不可空的结构。
伊蒙·纳邦

0
class Item{  
 bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
}

您的解决方案适用于一个物业,我应该已经指定我有同样的项目的许多特性,以检查空/零点
nailitdown

0

别忘了,对于字符串,您可以随时使用:

String.IsNullOrEmpty(str)

代替:

str==null || str==""

1
问题与“ 0”比较,不是一个空字符串。
dance2die

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.