Типи, що дозволяють опустити: кращий спосіб перевірити нуль чи нуль у 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);
}

Чи є кращий спосіб?

Відповіді:


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
Джошуа Шеннон

3
@nailitdown: (частина II) Ваш оператор повернення виглядатиме як return (значення ?? за замовчуванням (T)). Дорівнює (valueToCheck);
Джошуа Шеннон,

2
Якщо ви скоротите його до "IsNullOr (0)", це, природно, читатиметься як "є нульовим або нульовим"
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буде порівнюватися з null( default(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); }
Бехзад Ебрагімі

39

Хоча мені дуже подобається прийнята відповідь, я думаю, що для повноти слід зазначити і цей варіант:

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

Це рішення


Though Однак це не повинно впливати на ваше рішення, оскільки такі види мікрооптимізації навряд чи можуть щось змінити.


19

Це насправді просто розширення прийнятої відповіді Фредді Ріоса лише за допомогою 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) на нуль, оскільки ми маємо справу з типами значень або структурами! Це також означає, що ми можемо спокійно вважати, що T valueToCheck не буде нульовим; Пам'ятаєте тут, що Т? є скороченим 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

Я згоден з використанням оператора.

Якщо ви маєте справу зі рядками, використовуйте if (String.IsNullOrEmpty (myStr))


2

чи є кращий спосіб?

Ну, якщо ви дійсно шукаєте кращого шляху, ви, ймовірно, можете додати ще один шар абстракції поверх Rate. Ну ось щось, що я щойно придумав, використовуючи Nullable Design Pattern.

за допомогою системи;
за допомогою System.Collections.Generic;

простір імен NullObjectPatternTest
{
    програма громадського класу
    {
        public static void Main (рядок [] аргументи)
        {
            var items = новий список
                            {
                                новий елемент (RateFactory.Create (20)),
                                новий елемент (RateFactory.Create (null))
                            };

            PrintPriceForItems (елементи);
        }

        private static void PrintPriceForItems (IEnumerable items)
        {
            foreach (змінний елемент у елементах)
                Console.WriteLine ("Ціна товару: {0: C}", item.GetPrice ());
        }
    }

    публічний абстрактний клас ItemBase
    {
        публічна анотація Rate Rate {get; }
        public int GetPrice ()
        {
            // НЕ потрібно перевіряти, чи Rate == 0 або Rate == null
            повернення 1 * Rate.Value;
        }
    }

    публічний клас Item: ItemBase
    {
        приватний рейтинг лише для читання _Rate;
        загальнодоступна швидкість перевизначення {get {return _Rate; }}
        публічний товар (ставка ставки) {_Rate = ставка; }
    }

    загальнодоступний клас RateFactory
    {
        public static Rate Create (int? rateValue)
        {
            якщо (! rateValue || rateValue == 0) 
                повернути новий NullRate ();
            повернути нову ставку (rateValue);
        }
    }

    громадський клас Оцініть
    {
        public int Value {get; встановити; }
        загальнодоступний віртуальний bool HasValue {get {return (Значення> 0); }}
        публічна ставка (int value) {Value = value; }
    }

    публічний клас NullRate: Оцініть
    {
        public override bool HasValue {get {return false; }}
        public NullRate (): base (0) {}
    }
}

1
я думаю, ти маєш рацію, що усунення нульових значень на якомусь попередньому етапі було б правильним шляхом
nailitdown

Не зовсім. Існує поняття під назвою "Рефакторинг". Ви можете переформатувати свій код у бік кращого зразка або до кращої структури. На пізніх етапах завжди можна усунути значення, що допускають обнулення.
dance2die

2

Зразок коду не вдасться. Якщо obj є нульовим, тоді obj.ToString () призведе до нульового виключення посилання. Я б скоротив процес і перевірив наявність нульового obj на початку вашої допоміжної функції. Щодо вашого фактичного запитання, який тип ви перевіряєте на нуль чи нуль? У String є чудова функція IsNullOrEmpty, мені здається, це було б великим використанням методів розширення для реалізації методу IsNullOrZero на int? типу.

Редагувати: Пам'ятаєте, "?" це просто компілятор цукру для типу INullable, тому ви, ймовірно, можете взяти INullable як парм, а потім jsut порівняти його з нулем (parm == null), а якщо не нуль, порівняти з нулем.


привітання за вилов цієї помилки - у цьому проекті мені потрібно перевірити проти int ?, double ?, decimal? і т. д. саме тому я використовую "об'єкт"
nailitdown

Пам'ятаєте, "?" це просто компілятор цукру для типу INullable <T>, тому ви, напевно, можете взяти INullable <T> як парм, а потім jsut порівняти його з нулем (parm == null), а якщо не нуль, порівняти з нулем.
Уолден Леверіч,

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

1
Роздуми проходять повільно , будьте обережні з подібними рішеннями. Я не заперечую проти роздумів, але я б не очікував, що це буде в такій "простій" функції, і це мене застигне.
Walden Leverich

це насправді перевіряє на нуль?
nailitdown

Насправді ні. Activator.CreateInstance (obj.GetType ()) поверне null для типів, що допускають обнулення, я вважаю.
конфігуратор

@configurator: коли типові типи, що мають значення, мають значення, вони встановлюються як основна структура, тобто, таким чином, це не буде створювати нульові значення, що мають нульовий статус, а структуру, що не має нульового значення за замовчуванням.
Eamon Nerbonne

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

ваше рішення працює для однієї властивості, я мав би вказати, що у мене є багато властивостей того самого елемента, щоб перевірити нуль / нуль
nailitdown

0

Не забувайте, для рядків ви завжди можете використовувати:

String.IsNullOrEmpty(str)

Замість:

str==null || str==""

1
Питання порівнюється з "0" не порожнім рядком.
dance2die

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.