Tipi nullable: modo migliore per verificare null o zero in c #


85

Sto lavorando a un progetto in cui trovo che sto verificando quanto segue in molti, molti posti:

if(item.Rate == 0 || item.Rate == null) { }

più come curiosità che altro, qual è il modo migliore per verificare entrambi i casi?

Ho aggiunto un metodo di supporto che è:

public static bool nz(object obj)
{
    var parsedInt = 0;
    var parsed = int.TryParse(obj.ToString(), out parsedInt);
    return IsNull(obj) || (parsed && parsedInt == 0);
}

Esiste un modo migliore?

Risposte:


162

mi piace if ((item.Rate ?? 0) == 0) { }

Aggiornamento 1:

Puoi anche definire un metodo di estensione come:

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

E usalo in questo modo:

if(item.IsNullOrValue(0)){} // ma non ci guadagni molto


3
grazie - molto succinto! Ero preoccupato per la leggibilità, ma sono giunto alla conclusione che sarebbe stato perfettamente leggibile se avessi effettivamente capito ?? operatore.
— nailitdown

2
Dovresti usare il metodo di estensione; sebbene sia leggibile al momento della scrittura, questo piccolo frammento di codice richiede una frazione di pensiero, il che significa che se provi a leggere il codice e lo usa, sei distratto dal tuo problema principale.
— configuratore

11
@nailitdown: non proprio, hai solo bisogno di un metodo di estensione per Nullable <T>. Doppio? è un alias per Nullable <double>. La tua firma sarà simile a: public static bool IsNullOrValue <T> (this Nullable <T>, t valueToCheck) dove T: struct
— Joshua Shannon

3
@nailitdown: (parte II) La tua dichiarazione di ritorno sarebbe quindi come return (value ?? default (T)). Equals (valueToCheck);
— Joshua Shannon

2
Se abbreviato in "IsNullOr (0)", verrebbe naturalmente letto come "è nullo o zero"
— ChrisFox

41

Usare i generici:

static bool IsNullOrDefault<T>(T value)
{
    return object.Equals(value, default(T));
}

//...
double d = 0;
IsNullOrDefault(d); // true
MyClass c = null;
IsNullOrDefault(c); // true

Se Tè un tipo di riferimento , valueverrà confrontato con null( default(T)), altrimenti, se Tè value type, diciamo double, default(t)è 0d, per bool is false, per char is '\0'e così via ...


1
metodo di estensione:public static bool IsNullOrValue<T>(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
— Behzad Ebrahimi

39

Sebbene mi piaccia abbastanza la risposta accettata, penso che, per completezza, dovrebbe essere menzionata anche questa opzione:

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

Questa soluzione


¹ Ciò non dovrebbe influenzare la tua decisione, tuttavia, poiché è improbabile che questo tipo di microottimizzazione faccia la differenza.


19

Questa è davvero solo un'espansione della risposta accettata di Freddy Rios usando solo i 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));
}

NOTA non abbiamo bisogno di controllare default (T) per null poiché abbiamo a che fare con tipi di valore o strutture! Ciò significa anche che possiamo tranquillamente presumere che T valueToCheck non sarà nullo; Ricordi qui quella T? è una scorciatoia Nullable <T> quindi aggiungendo l'estensione a Nullable <T> otteniamo il metodo in int ?, double ?, bool? eccetera.

Esempi:

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

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

bool? z = false;
z.IsNullOrDefault(); //true

2

Sono d'accordo con l'utilizzo del ?? operatore.

Se hai a che fare con stringhe usa if (String.IsNullOrEmpty (myStr))


2

Esiste un modo migliore?

Bene, se stai davvero cercando un modo migliore, probabilmente puoi aggiungere un altro livello di astrazione oltre a Rate. Bene, ecco qualcosa che ho appena inventato usando Nullable Design Pattern.

using System;
using System.Collections.Generic;

spazio dei nomi NullObjectPatternTest
{
    programma di classe pubblica
    {
        public static void Main (string [] args)
        {
            elementi var = nuovo elenco
                            {
                                nuovo elemento (RateFactory.Create (20)),
                                nuovo elemento (RateFactory.Create (null))
                            };

            PrintPricesForItems (articoli);
        }

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

    classe astratta pubblica ItemBase
    {
        abstract pubblico Rate Rate {get; }
        public int GetPrice ()
        {
            // NON è necessario verificare se Rate == 0 o Rate == null
            return 1 * Rate.Value;
        }
    }

    classe pubblica Item: ItemBase
    {
        privato readonly Rate _Rate;
        public override Rate Rate {get {return _Rate; }}
        Articolo pubblico (Tasso tasso) {_Rate = tasso; }
    }

    classe pubblica sigillata RateFactory
    {
        tasso statico pubblico Crea (int? rateValue)
        {
            if (! rateValue || rateValue == 0) 
                return new NullRate ();
            return new Rate (rateValue);
        }
    }

    tasso di classe pubblica
    {
        public int Valore {get; impostato; }
        bool virtuale pubblico HasValue {get {return (Value> 0); }}
        Tasso pubblico (valore int) {Valore = valore; }
    }

    public class NullRate: Rate
    {
        public override bool HasValue {get {return false; }}
        public NullRate (): base (0) {}
    }
}

1
Penso che tu abbia ragione sul fatto che eliminare i valori nulli in una fase precedente sarebbe stata la strada da percorrere
— nailitdown

Non esattamente. C'è un concetto chiamato "Refactoring". Puoi effettuare il refactoring del codice verso un modello migliore o una struttura migliore. È sempre possibile eliminare i valori nullable nelle fasi successive.
— dance2die

2

L'esempio di codice fallirà. Se obj è null, obj.ToString () risulterà in un'eccezione di riferimento null. Abbreviare il processo e verificare la presenza di un oggetto nullo all'inizio della funzione di supporto. Per quanto riguarda la tua domanda effettiva, qual è il tipo che stai verificando per null o zero? Su String c'è una grande funzione IsNullOrEmpty, mi sembra che questo sarebbe un ottimo uso dei metodi di estensione per implementare un metodo IsNullOrZero sull'int? genere.

Modifica: ricorda, il "?" è solo zucchero del compilatore per il tipo INullable, quindi potresti probabilmente prendere un INullable come parametro e quindi confrontarlo con null (parm == null) e se non null confrontare con zero.


applausi per aver catturato quel bug - in questo progetto
— devo

Ricorda il '?' è solo zucchero del compilatore per il tipo INullable <T>, quindi potresti probabilmente prendere un INullable <T> come parametro e quindi confrontarlo con null (parm == null) e se non null confrontare con zero.
— Walden Leverich

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

1
La riflessione è lenta , fai attenzione a soluzioni come questa. Non mi oppongo alla riflessione, ma non me lo aspetterei in una funzione "semplice" come questa e mi prenderebbe alla sprovvista.
— Walden Leverich

questo verifica effettivamente zero?
— nailitdown

In realtà no. Activator.CreateInstance (obj.GetType ()) restituirà null per i tipi nullable, credo.
— configuratore

@configurator: quando i tipi nullable sono boxed, sono boxed come la struttura sottostante, cioè, quindi questo non costruirà una struttura nullable con valori null, ma una struttura non nullable con valori predefiniti.
— Eamon Nerbonne

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

la tua soluzione funziona per una proprietà, avrei dovuto specificare che ho molte proprietà dello stesso articolo per verificare null / zero
— nailitdown

0

Non dimenticare, per le stringhe, puoi sempre usare:

String.IsNullOrEmpty(str)

Invece di:

str==null || str==""

1
La domanda viene confrontata con "0" non una stringa vuota.
— dance2die

-1

Un passo avanti rispetto alla bella risposta di Joshua Shannon . Ora con la prevenzione di boxe / 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));
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.