Обнуляемые типы: лучший способ проверить наличие нуля или нуля в c # - PullRequest
69 голосов
/ 11 марта 2009

Я работаю над проектом, где я нахожу, что проверяю следующее во многих, многих местах:

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

Есть ли лучший способ?

Ответы [ 11 ]

133 голосов
/ 11 марта 2009

Мне нравится if ((item.Rate ?? 0) == 0) { }

Обновление 1:

Вы также можете определить метод расширения, например:

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

И используйте это так:

if(item.IsNullOrValue(0)){} // но вы мало что получаете от этого

39 голосов
/ 11 марта 2009

Использование дженериков:

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' и так далее ...

27 голосов
/ 15 марта 2013

Хотя мне очень нравится принятый ответ, я думаю, что для полноты следует упомянуть и эту опцию:

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

Это решение


¹ Однако это не должно влиять на ваше решение, поскольку эти виды микрооптимизации вряд ли будут иметь какое-либо значение.

17 голосов
/ 11 марта 2009

Это на самом деле просто расширение принятого ответа Фредди Риоса только с использованием 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 не будет нулевым; Помните здесь, что T? это сокращение Nullable , поэтому, добавив расширение к Nullable , мы получим метод в int ?, double ?, bool? и т.д.

Примеры:

double? x = null;
x.IsNullOrDefault(); //true

int? y = 3;
y.IsNullOrDefault(); //false

bool? z = false;
z.IsNullOrDefault(); //true
2 голосов
/ 11 марта 2009

есть ли лучший способ?

Что ж, если вы действительно ищете лучший способ, вы можете добавить еще один слой абстракции поверх Rate. Ну вот кое-что, что я только что придумал, используя Nullable Design Pattern.

using System;
using System.Collections.Generic;

namespace NullObjectPatternTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var items = new List
                            {
                                new Item(RateFactory.Create(20)),
                                new Item(RateFactory.Create(null))
                            };

            PrintPricesForItems(items);
        }

        private static void PrintPricesForItems(IEnumerable items)
        {
            foreach (var item in items)
                Console.WriteLine("Item Price: {0:C}", item.GetPrice());
        }
    }

    public abstract class ItemBase
    {
        public abstract Rate Rate { get; }
        public int GetPrice()
        {
            // There is NO need to check if Rate == 0 or Rate == null
            return 1 * Rate.Value;
        }
    }

    public class Item : ItemBase
    {
        private readonly Rate _Rate;
        public override Rate Rate { get { return _Rate; } }
        public Item(Rate rate) { _Rate = rate; }
    }

    public sealed class RateFactory
    {
        public static Rate Create(int? rateValue)
        {
            if (!rateValue || rateValue == 0) 
                return new NullRate();
            return new Rate(rateValue);
        }
    }

    public class Rate
    {
        public int Value { get; set; }
        public virtual bool HasValue { get { return (Value > 0); } }
        public Rate(int value) { Value = value; }
    }

    public class NullRate : Rate
    {
        public override bool HasValue { get { return false; } }
        public NullRate() : base(0) { }
    }
}
2 голосов
/ 11 марта 2009

Ваш пример кода не удастся. Если obj имеет значение null, то obj.ToString () приведет к исключению нулевой ссылки. Я бы сократил процесс и проверил наличие нулевого объекта в начале вашей вспомогательной функции. Что касается вашего фактического вопроса, какой тип вы проверяете на ноль или ноль? На String есть отличная функция IsNullOrEmpty, мне кажется, что это было бы отличным использованием методов расширения для реализации метода IsNullOrZero в int? типа.

Редактировать: Помните, "?" это просто сахар компилятора для типа INullable, так что вы, вероятно, могли бы взять INullable в качестве параметра и затем сравнить его со значением null (parm == null), а если нет, сравнить со значением ноль.

2 голосов
/ 11 марта 2009

Я согласен с использованием ?? оператор.

Если вы имеете дело со строками, используйте if (String.IsNullOrEmpty (myStr))

0 голосов
/ 19 октября 2018

На шаг дальше от Джошуа Шеннон приятно ответ . Теперь с предотвращением бокс / распаковка :

public static class NullableEx
{
    public static bool IsNullOrDefault<T>(this T? value)
        where T : struct
    {
        return EqualityComparer<T>.Default.Equals(value.GetValueOrDefault(), default(T));
    }
}
0 голосов
/ 11 марта 2009

Не забывайте, что для строк вы всегда можете использовать:

String.IsNullOrEmpty(str)

Вместо:

str==null || str==""
0 голосов
/ 11 марта 2009
class Item{  
 bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
}
...