W VB.NET dzieje się tak:
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false") '' <-- I got this. Why?
End If
Ale w C # dzieje się tak:
decimal? x = default(decimal?);
decimal? y = default(decimal?);
y = 5;
if (x != y)
{
Debug.WriteLine("true"); // <-- I got this -- I'm with you, C# :)
}
else
{
Debug.WriteLine("false");
}
Dlaczego jest różnica?
default(decimal?)
zwraca 0, nienull
.null
If
warunkach VB nie trzeba oceniać jako wartości logicznej ... uuuugh EDIT: WięcNothing <> Anything = Nothing
co skutkujeIf
objęciem trasy negatyw / else.Odpowiedzi:
VB.NET i C # .NET to różne języki, stworzone przez różne zespoły, które przyjęły różne założenia dotyczące użycia; w tym przypadku semantyka porównania NULL.
Osobiście preferuję semantykę VB.NET, która w istocie nadaje NULL semantykę „Jeszcze nie wiem”. Następnie porównanie 5 do „Jeszcze nie wiem”. jest naturalnie „jeszcze nie wiem”; tj. NULL. Ma to dodatkową zaletę polegającą na odzwierciedlaniu zachowania wartości NULL w (większości, jeśli nie we wszystkich) bazach danych SQL. Jest to również bardziej standardowa (niż w języku C #) interpretacja logiki trójwartościowej, jak wyjaśniono tutaj .
Zespół C # przyjął różne założenia dotyczące tego, co oznacza wartość NULL, co spowodowało pokazaną różnicę w zachowaniu. Eric Lippert napisał bloga o znaczeniu NULL w C # . Per Eric Lippert: „Pisałem też o semantyce wartości null w VB / VBScript i JScript tu i tutaj ”.
W każdym środowisku, w którym możliwe są wartości NULL, nie można już uznawać, że Prawo Wyłączonego Środka (tj. Że A lub ~ A jest tautologicznie prawdziwe) nie może już być oparte na prawach.
Aktualizacja:
A
bool
(w przeciwieństwie do abool?
) może przyjmować tylko wartości PRAWDA i FAŁSZ. Jednak implementacja języka NULL musi zdecydować, w jaki sposób NULL propaguje się przez wyrażenia. W VB wyrażenia5=null
i5<>null
OBIE zwracają fałsz. W języku C # z porównywalnych wyrażeń5==null
i5!=null
tylkodrugiepierwsze [zaktualizowane 2014-03-02 - PG] zwraca wartość false. Jednak w KAŻDYM środowisku, które obsługuje wartość null, na programiście spoczywa obowiązek znajomości tabel prawdy i propagacji wartości null używanych przez ten język.Aktualizacja
Artykuły na blogu Erica Lipperta (wymienione w jego komentarzach poniżej) na temat semantyki są teraz dostępne pod adresem:
30 września 2003 - Całe mnóstwo niczego
1 października 2003 - Trochę więcej o niczym
źródło
bool
nie może mieć 3 wartości, tylko dwie. Tobool?
może mieć trzy wartości.operator ==
ioperator !=
oba zwracająbool
, niebool?
, niezależnie od typu operandów. Ponadtoif
oświadczenie może akceptować tylko abool
, a niebool?
.5=null
i5<>null
nie są prawidłowe. I5 == null
czy5 != null
na pewno jest to druga, która powracafalse
?Ponieważ
x <> y
zwracaNothing
zamiasttrue
. Po prostu nie jest zdefiniowany, ponieważx
nie jest zdefiniowany. (podobnie do SQL null).Uwaga: VB.NET
Nothing
<> C #null
.Musisz także porównać wartość a
Nullable(Of Decimal)
tylko wtedy, gdy ma wartość.Więc VB.NET powyżej porównuje się podobnie do tego (który wygląda mniej niepoprawnie):
Specyfikacja języka VB.NET :
Na przykład:
źródło
Spójrz na wygenerowany CIL (przekonwertowałem oba na C #):
DO#:
Visual Basic:
Zobaczysz, że porównanie w Visual Basic zwraca wartość Nullable <bool> (nie bool, false lub true!). A undefined przekonwertowany na bool jest fałszywy.
Nothing
w porównaniu z tym, co jest zawszeNothing
, a nie fałszem w Visual Basic (to jest to samo, co w SQL).źródło
Zaobserwowany tu problem jest szczególnym przypadkiem bardziej ogólnego problemu, polegającego na tym, że liczba różnych definicji równości, które mogą być przydatne przynajmniej w niektórych okolicznościach, przekracza liczbę powszechnie dostępnych sposobów ich wyrażenia. W niektórych przypadkach ten problem pogarsza niefortunne przekonanie, że mylące jest posiadanie różnych metod testowania równości, które dają różne wyniki, a takiego zamieszania można uniknąć, jeśli różne formy równości dają takie same wyniki, kiedy tylko jest to możliwe.
W rzeczywistości podstawową przyczyną nieporozumień jest błędne przekonanie, że należy oczekiwać, że różne formy testowania równości i nierówności dadzą ten sam wynik, niezależnie od faktu, że różne semantyki są przydatne w różnych okolicznościach. Na przykład, z arytmetycznego punktu widzenia, warto mieć możliwość porównania,
Decimal
które różnią się tylko liczbą końcowych zer, jako równe. Podobnie dladouble
wartości takich jak dodatnie zero i ujemne zero. Z drugiej strony, z punktu widzenia buforowania lub internowania, taka semantyka może być śmiertelna. Załóżmy na przykład, że ktoś maDictionary<Decimal, String>
taki, którymyDict[someDecimal]
powinien być równysomeDecimal.ToString()
. Taki przedmiot wydawałby się rozsądny, gdyby ktoś miał ich wieleDecimal
wartości, które ktoś chciał przekonwertować na łańcuch i spodziewał się wielu duplikatów. Niestety, gdyby wykorzystano takie buforowanie do konwersji 12,3 mi 12,40 m, a następnie 12,30 mi 12,4 m, te ostatnie wartości dałyby „12,3” i „12,40” zamiast „12,30” i „12,4”.Wracając do omawianej sprawy, istnieje więcej niż jeden rozsądny sposób porównywania obiektów dopuszczających wartość zerową pod kątem równości. C # przyjmuje stanowisko, że jego
==
operator powinien odzwierciedlać zachowanieEquals
. VB.NET stoi na stanowisku, że jego zachowanie powinno odzwierciedlać zachowanie niektórych innych języków, ponieważ każdy, kto chce,Equals
może użyć tego zachowaniaEquals
. W pewnym sensie właściwym rozwiązaniem byłoby posiadanie trójczynnikowej konstrukcji „jeśli” i wymaganie, aby jeśli wyrażenie warunkowe zwracało trójwartościowy wynik, kod musiał określać, co powinno się wydarzyć wnull
przypadku. Ponieważ nie jest to możliwe w przypadku języków, którymi są, kolejną najlepszą alternatywą jest po prostu nauczenie się, jak działają różne języki i uznanie, że nie są one tym samym.Nawiasem mówiąc, operator „Is” języka Visual Basic, którego brakuje w C, może służyć do testowania, czy obiekt dopuszczający wartość null jest w rzeczywistości pusty. Chociaż można rozsądnie zastanawiać się, czy
if
test powinien akceptować aBoolean?
, użyteczną funkcją jest zwracanie normalnych operatorów porównaniaBoolean?
zamiastBoolean
wywoływania ich na typach dopuszczających wartość null. Nawiasem mówiąc, w VB.NET, jeśli ktoś spróbuje użyć operatora równości zamiastIs
, otrzyma ostrzeżenie, że wynik porównania zawsze będzieNothing
i należy go użyć,Is
jeśli chce się sprawdzić, czy coś jest zerowe.źródło
== null
. Testowanie, czy typ wartości dopuszczającej wartość null ma wartość, jest wykonywane przez.hasValue
. Jaki jest pożytek zIs Nothing
operatora? C # ma,is
ale testuje zgodność typu. W świetle powyższego naprawdę nie jestem pewien, co próbuje powiedzieć twój ostatni akapit.null
, chociaż oba języki traktują to jako cukier składniowy doHasValue
sprawdzenia, przynajmniej w przypadkach, gdy typ jest znany (nie jestem pewien jaki kod jest generowany dla typów generycznych).Może ten post ci pomoże:
Jeśli dobrze pamiętam, „nic” w VB oznacza „wartość domyślna”. W przypadku typu wartości jest to wartość domyślna, w przypadku typu referencyjnego byłaby to null. Zatem przypisanie niczego do struktury nie stanowi żadnego problemu.
źródło
<>
operatora w języku VB i tego, jak działa on na typach dopuszczających wartość null.To zdecydowanie dziwaczność VB.
W języku VB, jeśli chcesz porównać dwa typy dopuszczające wartość null, powinieneś użyć
Nullable.Equals()
.W Twoim przykładzie powinno to być:
źródło
Nullable<>.Equals()
. Można by się spodziewać, że będzie działać w ten sam sposób (co robi C #).Nullable
nie istniała w pierwszych wersjach .NET, została utworzona po tym, jak C # i VB.NET były niedostępne przez jakiś czas i już określały ich zachowanie w zakresie propagacji zerowej. Czy naprawdę oczekujesz, że język będzie spójny z typem, który nie powstanie przez kilka lat? Z punktu widzenia programisty VB.NET jest to Nullable.Equals, które nie są zgodne z językiem, a nie odwrotnie. (Biorąc pod uwagę, że C # i VB używają tej samejNullable
definicji, nie było sposobu, aby była spójna z obydwoma językami.)Twój kod VB jest po prostu nieprawidłowy - jeśli zmienisz „x <> y” na „x = y”, nadal będziesz miał jako wynik „fałsz”. Najczęstszym sposobem wyrażenia this dla wystąpień dopuszczających wartość null jest „Not x.Equals (y)”, co daje takie samo zachowanie jak „x! = Y” w C #.
źródło
x
taknothing
, w takim przypadkux.Equals(y)
zgłosi wyjątek.