Najlepszy sposób na sprawdzenie wartości zerowej bool w wyrażeniu warunkowym (jeśli…)

207

Zastanawiałem się, jaka była najbardziej czysta i zrozumiała składnia do sprawdzania warunków na zerowalnych wartościach logicznych.

Czy następujący dobry lub zły styl kodowania? Czy istnieje sposób, aby lepiej / bardziej wyrazić ten stan?

bool? nullableBool = true;
if (nullableBool ?? false) { ... }
else { ... }

szczególnie część if (nullableBool ?? false) . Nie podoba mi się if (x.HasValue && x.Value)styl ...

(nie jestem pewien, czy pytanie zostało zadane wcześniej ... nie można znaleźć czegoś podobnego przy wyszukiwaniu)

FireSnake
źródło

Odpowiedzi:

361

Myślę, że wiele osób koncentruje się na tym, że ta wartość jest zerowa, i nie myślą o tym, czego naprawdę chcą :)

bool? nullableBool = true;
if (nullableBool == true) { ... } // true
else { ... } // false or null

Lub jeśli chcesz więcej opcji ...

bool? nullableBool = true;
if (nullableBool == true) { ... } // true
else if (nullableBool == false) { ... } // false
else { ... } // null

(nullableBool == true)nigdy nie zwróci prawdy, jeśli bool? jest zerowy: P

Artiom Chilaru
źródło
2
Nie zdawałem sobie sprawy, że takie zerowe porównanie ma takie znaczenie. Szczegóły można znaleźć na stronie msdn.microsoft.com/en-us/library/2cf62fcy.aspx
Micah Zoltu
79

Co powiesz na użycie GetValueOrDefault , która jest dość intuicyjna i pozwala na użycie dowolnej domyślnej wartości:

if (nullableBool.GetValueOrDefault(false)) {
}
Lucero
źródło
6
W zależności od kontekstu takie podejście może rzucićSystem.NotSupportedException: LINQ to Entities does not recognize the method 'Boolean GetValueOrDefault()' method, and this method cannot be translated into a store expression.
Nano Taboada
3
Podoba mi się to podejście, ponieważ działa również w instrukcji non-if (tj. Przypisanie).
paultechguy,
48

Może ci się to nie podobać, ale osobiście uważam

if (x.HasValue && x.Value)

najbardziej czytelny. Wyjaśnia, że ​​pracujesz z typem zerowalnym i wyjaśnia, że ​​najpierw sprawdzasz, czy typ zerowalny ma wartość, zanim zaczniesz działać na nim warunkowo.

Jeśli weźmiesz swoją wersję i zamienisz zmienną na x, to będzie ona brzmiała:

if (x ?? false)

Czy to tak jasne? Czy to oczywiste, że x jest typem zerowalnym? Pozwolę ci zdecydować.

Dan Diplo
źródło
afaik, ?? działa tylko na typy zerowalne. Dodatkowo zmienna powinna mieć ładniejszą nazwę niż x :)
FireSnake
5
Przez „typ zerowalny” rozumiałem konkretnie typy System.Nullable. Dowolny typ odwołania może mieć wartość NULL. Ponadto, jeśli musisz użyć typu zmiennej jako części jej nazwy, oznacza to, że kod nie jest czysty.
Dan Diplo,
@DanDiplo Jak napisać do tego UT?
Prashant Yadav
xjest w porządku i czasami jest czystszy; to var openOrders = orders.Where(x=>x.Open ?? false)
znaczy
21

Jeśli chcesz traktować nulljako fałsz, powiedziałbym, że najbardziej zwięzłym sposobem na to jest użycie operatora zerowej koalescencji ( ??), jak to opisano:

if (nullableBool ?? false) { ... }
Oded
źródło
8

Pomyśl o bool? ponieważ mają 3 wartości, to staje się łatwiejsze:

if (someNullableBool == true)     // only if true
if (someNullableBool == false)    // only if false
if (someNullableBool == null)     // only if null

źródło
8

Użyj rozszerzeń.

public static class NullableMixin {
    public static bool IsTrue(this System.Nullable<bool> val) {
        return val == true;
    }
    public static bool IsFalse(this System.Nullable<bool> val) {
        return val == false;
    }
    public static bool IsNull(this System.Nullable<bool> val) {
        return val == null;
    }
    public static bool IsNotNull(this System.Nullable<bool> val) {
        return val.HasValue;
    }
}


Nullable<bool> value = null;
if(value.IsTrue()) {
// do something with it
}
Andrey Frolov
źródło
Co jeśli chcesz uznać nullza true?
Thibault Falise
IsTrue () | IsNull () .. :) Odtworzyłem logikę działania SQL z wartościami null. Myślę, że jest to najbardziej przejrzysta i zrozumiała składnia.
Andrey Frolov,
Powinien to być publiczny statyczny bool IsFalse (this System.Nullable val) {return! Val ?? prawdziwe; } uważać zero za fałszywe
Michael Freidgeim
2
Może brakować średników (;) w dwóch ostatnich metodach (tj. IsNull i IsNotNull)
glenn garson
4

Pozwala sprawdzić, jak zdefiniowane jest porównanie z wartością null:

static void Main()
    {
        Console.WriteLine($"null != null  => {null != null}");
        Console.WriteLine($"null == null  => {null == null}");
        Console.WriteLine($"null != true  => {null != true}");
        Console.WriteLine($"null == true  => {null == true}");
        Console.WriteLine($"null != false => {null != false}");
        Console.WriteLine($"null == false => {null == false}");
    }

a wyniki to:

null != null  => False                                                                                                                                                                                                                                  
null == null  => True                                                                                                                                                                                                                                   
null != true  => True                                                                                                                                                                                                                                   
null == true  => False                                                                                                                                                                                                                                  
null != false => True                                                                                                                                                                                                                                   
null == false => False

Możesz więc bezpiecznie używać:

// check if null or false
if (nullable != true) ...

// check if null or true
if (nullable != false) ...

// check if true or false
if (nullable != null) ...
Sz. Moncz
źródło
Zastanawiam się tylko, dlaczego nie możemy tego zrobić, jeśli (nullable) .... to by się dało, ale trzeba zachować ostrożnośćif(nullable)...else if(!nulllable)...else..
IronHide
Powiedziałbym, że w ostatnich latach styl kodowania (ze względu na dostępność narzędzi takich jak stylecop, analizatory itp.) Coraz bardziej preferuje jednoznaczny, jasny kod „potwierdzający zamiar” (np. Zalecający stosowanie niepotrzebnych nawiasów tylko w celu potwierdzenia zamierzonego użycia priorytetów operatorów lub za pomocą różnych systemów adnotacji / umów). IMO wprowadzając taką składnię spowodowałoby znacznie więcej zamieszania ze względu na poziom niejasności, w jaki sposób obsługiwane są wartości null, niż korzyści.
Sz. Moncz
4

Właściwie uważam, że (nullableBool ?? false)jest to uzasadniona opcja, zwłaszcza gdy próbujesz ocenić zerowalne bool w linq.

Na przykład:
array.Select(v => v.nullableBool ?? false)
(from v in array where v.nullableBool ?? false)

Moim zdaniem jest czystszy w przeciwieństwie do:
array.Select(v => v.nullableBool.HasValue ? v.nullableBool.Value : false)
(from v in array where v.nullableBool.HasValue ? v.nullableBool.Value : false)

Zze
źródło
1

Jeśli chcesz testować tylko trueprzeciwko null/ false, jest to jeden, którego właśnie użyłem i czyta całkiem dobrze

bool? someCondition = null
if (someCondition.Equals(true))
...
ds4940
źródło
1
Nie otrzymujesz tutaj wyjątku zerowego odniesienia?
Chase Florell
@ChaseFlorell Musiałem dwukrotnie to sprawdzić w oknie VS Interactive. Należy więc pamiętać, że typem warunku jest Nullable <bool>. Nadal można wywoływać metody dziedziczone z obiektu (takiego jak Equals), HasValue i GetValueOrDefault , ale nie wartość
ds4940
ciekawe, teraz to widzę. Wciąż szkicowy dla typów referencyjnych dotnetfiddle.net/8cAI21
Chase
0

Myślę, że to zależy od ciebie. Z pewnością uważam, że podejście .HasValue jest bardziej czytelne, szczególnie w przypadku programistów nie znających ?? składnia.

Innym punktem zerowalnego typu logicznego jest to, że jest to tristate, więc możesz chcieć zrobić coś innego, gdy jest on po prostu zerowy, a domyślnie nie ma wartości false.

James Westgate
źródło
0

Biorąc pod uwagę wyliczenie

public enum PublishMode { Edit, View }

możesz to zrobić tak jak tutaj

 void MyMethod(PublishMode? mode)
    {
       var publishMode = mode ?? PublishMode.Edit;

//or
       if (mode?? PublishMode.Edit == someValue)
       ....
    }
Suseł
źródło
Brak odpowiedzi na pytanie, które dotyczy konkretnie nullable boolean.
ToolmakerSteve,
0

Jeśli znajdujesz się w sytuacji, w której nie masz kontroli nad tym, czy część warunku sprawdza wartość zerowalną, zawsze możesz wypróbować następujące czynności:

if( someInt == 6 && someNullableBool == null ? false : (bool)someNullableBool){
    //perform your actions if true
}

Wiem, że to nie jest dokładnie purystyczne podejście do umieszczenia trójki w instrukcji if, ale rozwiązuje problem w czysty sposób.

Jest to oczywiście ręczny sposób powiedzenia GetValueOrDefault(false)

MetalPhoenix
źródło
3
Rozwiązanie dostarczone w OP to to samo, ale tylko z dużo mniej rozdętym kodem. Nie jest to wcale korzystne.
Servy