Null yapılabilir türler: c # 'de null veya sıfırı kontrol etmenin daha iyi yolu


85

Birçok yerde aşağıdakileri kontrol ettiğimi fark ettiğim bir proje üzerinde çalışıyorum:

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

her şeyden çok merak olarak, her iki durumu da kontrol etmenin en iyi yolu nedir?

Yardımcı bir yöntem ekledim:

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

Daha iyi bir yol var mı?

Yanıtlar:


162

severim if ((item.Rate ?? 0) == 0) { }

Güncelleme 1:

Ayrıca aşağıdaki gibi bir uzatma yöntemi de tanımlayabilirsiniz:

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

Ve bunu şu şekilde kullanın:

if(item.IsNullOrValue(0)){} // ama ondan pek bir şey alamazsın


3
teşekkür ederim - çok kısa! Okunabilirlik konusunda endişeliydim, ancak gerçekten anlasaydım mükemmel okunabilir olacağı sonucuna vardım. Şebeke.
nailitdown

2
Uzatma yöntemini kullanmalısınız; Yazma anında okunabilir olsa da, bu küçük kod külçeleri biraz düşünmeyi gerektirir, yani kodu okumaya çalışırsanız ve kullanırsa - asıl probleminizden dikkatiniz dağılır.
konfigüratör

11
@nailitdown: gerçekten değil, sadece Nullable <T> için bir uzatma yöntemine ihtiyacınız var. çift? Nullable <double> için bir diğer addır. İmzanız şöyle görünecektir: public static bool IsNullOrValue <T> (bu Nullable <T>, t valueToCheck) burada T: struct
Joshua Shannon

3
@nailitdown: (bölüm II) Dönüş ifadeniz daha sonra return gibi görünecektir (değer ?? varsayılan (T)) Eşittir (valueToCheck);
Joshua Shannon

2
"IsNullOr (0)" olarak kısaltırsanız, doğal olarak "boş veya sıfır" olarak okunur
ChrisFox

41

Jenerik kullanımı:

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

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

Eğer Tbir referans türü ise , ( ) valueile karşılaştırılacak , aksi takdirde, eğer a ise , double, 0d diyelim , bool is , for char is vb.nulldefault(T)Tvalue typedefault(t)false'\0'


1
uzatma yöntemi:public static bool IsNullOrValue<T>(this T? value, T valueToCheck) where T : struct { return (value ?? default(T)).Equals(valueToCheck); }
Behzad Ebrahimi

39

Kabul edilen cevabı oldukça beğenmeme rağmen, bütünlük için bu seçeneğin de belirtilmesi gerektiğini düşünüyorum:

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

Bu çözüm


¹ Ancak, bu tür mikro optimizasyonların herhangi bir fark yaratması olası olmadığından, bu kararınızı etkilememelidir.


19

Bu gerçekten Freddy Rios'un yalnızca Generics kullanarak kabul ettiği yanıtın bir genişlemesidir.

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

NOT Değer türleri veya yapılarla uğraştığımız için default (T) 'yi null için kontrol etmemize gerek yoktur! Bu aynı zamanda T valueToCheck'in boş olmayacağını güvenle varsayabileceğimiz anlamına gelir; Buradaki T'yi hatırlıyor musun? Nullable <T> kısaltmasıdır, dolayısıyla Nullable <T> 'ye uzantıyı ekleyerek yöntemi int ?, double ?, bool? vb.

Örnekler:

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

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

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

2

Kullanmaya katılıyorum? Şebeke.

Dizelerle uğraşıyorsanız if (String.IsNullOrEmpty (myStr)) kullanın


2

daha iyi bir yol var mı?

Eğer gerçekten daha iyi bir yol arıyorsanız, Rate'in üstüne muhtemelen başka bir soyutlama katmanı ekleyebilirsiniz. İşte burada Nullable Design Pattern kullanarak bulduğum bir şey var.

Sistem kullanarak;
System.Collections.Generic kullanarak;

ad alanı NullObjectPatternTest
{
    public class Programı
    {
        public static void Main (string [] args)
        {
            var öğeler = yeni Liste
                            {
                                yeni Öğe (RateFactory.Create (20)),
                                yeni Öğe (RateFactory.Create (null))
                            };

            PrintPricesForItems (öğeler);
        }

        özel statik void PrintPricesForItems (IEnumerable öğeler)
        {
            foreach (öğelerdeki var öğe)
                Console.WriteLine ("Öğe Fiyatı: {0: C}", item.GetPrice ());
        }
    }

    public abstract sınıfı ItemBase
    {
        public abstract Rate Rate {get; }
        public int GetPrice ()
        {
            // Rate == 0 veya Rate == null olup olmadığını kontrol etmeye gerek YOKTUR
            return 1 * Rate.Value;
        }
    }

    public class Item: ItemBase
    {
        özel salt okunur Rate _Rate;
        genel geçersiz kılma Oranı Oranı {get {return _Rate; }}
        genel Öğe (Oran oranı) {_Rate = oran; }
    }

    genel mühürlenmiş sınıf RateFactory
    {
        public static Rate Create (int? rateValue)
        {
            eğer (! rateValue || rateValue == 0) 
                yeni NullRate () döndür;
            yeni Rate (rateValue) döndürür;
        }
    }

    public class Ücret
    {
        public int Value {get; Ayarlamak; }
        genel sanal bool HasValue {get {dönüş (Değer> 0); }}
        public Rate (int değer) {Değer = değer; }
    }

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

1
Sanırım daha önceki bir aşamada boş değerleri ortadan kaldırmanın yolu olacağında
haklısın

Tam olarak değil. "Yeniden düzenleme" adı verilen bir kavram var. Kodunuzu daha iyi bir modele veya daha iyi bir yapıya doğru yeniden düzenleyebilirsiniz. Daha sonraki aşamalarda her zaman null yapılabilir değerleri eleyebilirsiniz .
dance2die

2

Kod örneğiniz başarısız olacaktır. Obj null ise, obj.ToString () boş bir referans istisnası ile sonuçlanacaktır. Süreci kısa keser ve yardımcı işlevinizin başında boş bir nesneyi kontrol ederdim. Asıl sorunuza gelince, null veya sıfır için kontrol ettiğiniz tür nedir? String üzerinde harika bir IsNullOrEmpty işlevi var, bana bu int üzerinde IsNullOrZero yöntemini uygulamak için genişletme yöntemlerinin harika bir kullanımı olacak gibi görünüyor? yazın.

Düzenleme: '?' INullable türü için sadece bir derleyici şekerdir, bu nedenle muhtemelen parm olarak bir INullable alabilir ve sonra jsut ile null (parm == null) ile karşılaştırabilir ve null değilse sıfır ile karşılaştırabilirsiniz.


bu hatayı yakaladığım için şerefe - bu projede int ?, double ?, decimal ?, vb. ile kontrol
etmem gerekiyor

Unutma, '?' INullable <T> türü için sadece derleyici şekerdir, bu nedenle muhtemelen parm olarak bir INullable <T> alabilir ve sonra jsut ile null (parm == null) ile karşılaştırabilir ve null değilse sıfırla karşılaştırabilirsiniz.
Walden Leverich

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

1
Yansıma yavaştır , bunun gibi çözümlere dikkat edin. Düşünmeye itiraz etmiyorum, ancak bunun gibi "basit" bir işlevde olmasını beklemem ve beni hazırlıksız yakalar.
Walden Leverich

bu gerçekten sıfırı kontrol ediyor mu?
nailitdown

Aslında hayır. Activator.CreateInstance (obj.GetType ()) null yapılabilen türler için null döndüreceğine inanıyorum.
konfigüratör

@configurator: null yapılabilir türler kutu içine alındığında, temel yapı olarak kutuya alınırlar, yani bu, boş değerli bir null değeri oluşturmaz, ancak varsayılan değerli, null yapılamaz bir yapı oluşturur.
Eamon Nerbonne

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

çözümünüz bir mülk için çalışıyor, null / sıfır kontrol etmek için aynı öğenin birçok özelliğine sahip olduğumu belirtmeliydim
nailitdown

0

Unutmayın, dizeler için her zaman kullanabilirsiniz:

String.IsNullOrEmpty(str)

Onun yerine:

str==null || str==""

1
Soru, boş bir dizeyle değil "0" ile karşılaştırılır.
dance2die

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.