Nullable-Typen: Bessere Möglichkeit, in c # nach Null oder Null zu suchen

85

Ich arbeite an einem Projekt, bei dem ich an vielen, vielen Orten nach Folgendem suche:

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

Was ist der beste Weg, um beide Fälle zu überprüfen?

Ich habe eine Hilfsmethode hinzugefügt, die lautet:

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

Gibt es einen besseren Weg?

Nailitdown
quelle

Antworten:

161

ich mag if ((item.Rate ?? 0) == 0) { }

Update 1:

Sie können auch eine Erweiterungsmethode definieren wie:

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

Und benutze es so:

if(item.IsNullOrValue(0)){} // aber du bekommst nicht viel davon

eglasius
quelle
3
danke - sehr prägnant! Ich war besorgt über die Lesbarkeit, kam aber zu dem Schluss, dass es perfekt lesbar wäre, wenn ich die ?? Operator.
Nailitdown
2
Sie sollten die Erweiterungsmethode verwenden. Während es im Moment des Schreibens lesbar ist, erfordert dieses kleine Code-Nugget einen Bruchteil des Denkens. Wenn Sie also versuchen, Code zu lesen und ihn verwendet, werden Sie von Ihrem Hauptproblem abgelenkt.
Konfigurator
11
@nailitdown: Nicht wirklich, Sie benötigen nur eine Erweiterungsmethode für Nullable <T>. doppelt? ist ein Alias ​​für Nullable <double>. Ihre Signatur sieht folgendermaßen aus: public static bool IsNullOrValue <T> (diese Nullable <T>, t valueToCheck) wobei T: struct
Joshua Shannon
3
@nailitdown: (Teil II) Ihre return-Anweisung würde dann wie return aussehen (Wert ?? default (T)). Equals (valueToCheck);
Joshua Shannon
2
Wenn Sie es auf "IsNullOr (0)" verkürzen, würde es natürlich als "ist null oder null"
lauten
41

Generika verwenden:

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

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

Wenn Tes eine ist Referenztyp , valuewird im Vergleich zu null( default(T)), andernfalls, wenn Teine ist value type, sagen wir mal doppelt, default(t)ist 0T, für Bool ist false, für char ist '\0'und so weiter ...

Christian C. Salvadó
quelle
1
Verlängerungsmethode:public static bool IsNullOrValue<T>(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
Behzad Ebrahimi
39

Obwohl mir die akzeptierte Antwort sehr gefällt, denke ich, dass der Vollständigkeit halber auch diese Option erwähnt werden sollte:

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

Diese Lösung


¹ Dies sollte jedoch keinen Einfluss auf Ihre Entscheidung haben, da diese Art der Mikrooptimierung wahrscheinlich keinen Unterschied macht.

Heinzi
quelle
19

Dies ist wirklich nur eine Erweiterung der von Freddy Rios akzeptierten Antwort, die nur Generika verwendet.

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

HINWEIS Wir müssen Standard (T) nicht auf Null prüfen, da es sich entweder um Werttypen oder Strukturen handelt! Dies bedeutet auch, dass wir davon ausgehen können, dass T valueToCheck nicht null ist. Erinnerst du dich hier an das T? ist die Kurzform Nullable <T>. Wenn Sie also die Erweiterung zu Nullable <T> hinzufügen, erhalten Sie die Methode in int?, double?, bool? etc.

Beispiele:

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

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

bool? z = false;
z.IsNullOrDefault(); //true
Joshua Shannon
quelle
2

Ich bin mit der Verwendung der ?? Operator.

Wenn Sie mit Strings arbeiten, verwenden Sie if (String.IsNullOrEmpty (myStr))

Nick Josevski
quelle
2

Gibt es einen besseren Weg?

Wenn Sie wirklich nach einem besseren Weg suchen, können Sie wahrscheinlich zusätzlich zu Rate eine weitere Abstraktionsebene hinzufügen. Nun, hier ist etwas, das ich mir gerade mit Nullable Design Pattern ausgedacht habe.

using System;
using System.Collections.Generic;

Namespace NullObjectPatternTest
{
    öffentliches Klassenprogramm
    {
        public static void Main (string [] args)
        {
            var items = neue Liste
                            {
                                neues Element (RateFactory.Create (20)),
                                neues Element (RateFactory.Create (null))
                            };

            PrintPricesForItems (Elemente);
        }}

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

    öffentliche abstrakte Klasse ItemBase
    {
        public abstract Rate Rate {get; }}
        public int GetPrice ()
        {
            // Es muss NICHT geprüft werden, ob Rate == 0 oder Rate == null ist
            return 1 * Rate.Value;
        }}
    }}

    öffentliche Klasse Item: ItemBase
    {
        privat schreibgeschützt Rate _Rate;
        public override Rate Rate {get {return _Rate; }}
        öffentlicher Gegenstand (Rate Rate) {_Rate = Rate; }}
    }}

    öffentliche versiegelte Klasse RateFactory
    {
        public static Rate Create (int? rateValue)
        {
            if (! rateValue || rateValue == 0) 
                return new NullRate ();
            neue Rate zurückgeben (rateValue);
        }}
    }}

    öffentliche Klasse Rate
    {
        public int Value {get; einstellen; }}
        öffentlicher virtueller Bool HasValue {get {return (Wert> 0); }}
        public Rate (int value) {Wert = Wert; }}
    }}

    öffentliche Klasse NullRate: Rate
    {
        public override bool HasValue {get {return false; }}
        public NullRate (): base (0) {}
    }}
}}
dance2die
quelle
1
Ich denke, Sie haben Recht, dass das Eliminieren von Nullwerten zu einem früheren Zeitpunkt der richtige Weg gewesen wäre
Nailitdown
Nicht genau. Es gibt ein Konzept namens "Refactoring". Sie können Ihren Code in Richtung eines besseren Musters oder einer besseren Struktur umgestalten. Sie können jederzeit beseitigen Nullable - Werte in späteren Phasen.
Dance2die
2

Ihr Codebeispiel schlägt fehl. Wenn obj null ist, führt obj.ToString () zu einer Nullreferenzausnahme. Ich würde den Prozess abkürzen und zu Beginn Ihrer Hilfsfunktion nach einem Nullobjekt suchen. Was ist der Typ, den Sie für Ihre eigentliche Frage auf Null oder Null prüfen? Auf String gibt es eine großartige IsNullOrEmpty-Funktion. Mir scheint, dies wäre eine großartige Verwendung von Erweiterungsmethoden, um eine IsNullOrZero-Methode auf dem int zu implementieren. Art.

Edit: Erinnerst du dich an das '?' ist nur Compilerzucker für den Typ INullable, daher könnten Sie wahrscheinlich ein INullable als Parameter verwenden und es dann mit null (parm == null) vergleichen und wenn nicht null mit null vergleichen.

Walden Leverich
quelle
Prost, dass
du diesen Fehler entdeckt hast
Erinnerst du dich an das '?' ist nur Compilerzucker für den Typ INullable <T>, daher könnten Sie wahrscheinlich ein INullable <T> als Parameter verwenden und es dann mit null vergleichen (parm == null) und wenn nicht null mit null vergleichen.
Walden Leverich
0
public static bool nz(object obj)
{
    return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType()));
}

quelle
1
Die Reflexion ist langsam , seien Sie vorsichtig mit solchen Lösungen. Ich habe keine Einwände gegen Reflexion, aber ich würde es in einer "einfachen" Funktion wie dieser nicht erwarten und es würde mich überraschen.
Walden Leverich
prüft dies tatsächlich auf Null?
Nailitdown
Nicht wirklich. Activator.CreateInstance (obj.GetType ()) gibt meiner Meinung nach null für nullfähige Typen zurück.
Konfigurator
@configurator: Wenn nullfähige Typen eingerahmt sind, werden sie als zugrunde liegende Struktur eingerahmt, dh es wird keine nullwertfähige nullfähige, sondern eine nicht nullfähige Struktur mit Standardwert erstellt.
Eamon Nerbonne
0
class Item{  
 bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}}
}
dtroy
quelle
Ihre Lösung funktioniert für eine Eigenschaft, soll ich , dass ich viele Eigenschaften des gleichen Elements für null / null zu überprüfen angegeben haben
nailitdown
0

Vergessen Sie nicht, für Zeichenfolgen können Sie immer verwenden:

String.IsNullOrEmpty(str)

Anstatt:

str==null || str==""
Chris
quelle
1
Frage vergleicht mit "0" keine leere Zeichenfolge.
Dance2die
-1

Einen Schritt weiter von Joshua Shannons netter Antwort . Jetzt mit Verhinderung des Boxens / 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));
    }
}
Deilan
quelle