Przebiegł przez ten wiersz kodu:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Co oznaczają dwa znaki zapytania, czy jest to jakiś trójskładnikowy operator? W Google trudno jest szukać.
Przebiegł przez ten wiersz kodu:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Co oznaczają dwa znaki zapytania, czy jest to jakiś trójskładnikowy operator? W Google trudno jest szukać.
Odpowiedzi:
Jest to zerowy operator koalescencyjny i całkiem podobny do operatora trójskładnikowego (natychmiast-jeśli). Zobacz także ? Operator - MSDN .
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
rozwija się do:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
co dalej rozwija się do:
if(formsAuth != null)
FormsAuth = formsAuth;
else
FormsAuth = new FormsAuthenticationWrapper();
W języku angielskim oznacza to: „Jeśli cokolwiek jest po lewej stronie, nie jest zerowe, użyj tego, w przeciwnym razie użyj tego, co jest po prawej stronie”.
Pamiętaj, że możesz użyć dowolnej ich liczby po kolei. Poniższe oświadczenie przydzieli pierwsze niezerowe Answer#
do Answer
(jeśli wszystkie odpowiedzi są nieważne, to Answer
jest null):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
Warto również wspomnieć, podczas gdy powyższe rozwinięcie jest koncepcyjnie równoważne, wynik każdego wyrażenia jest oceniany tylko raz. Jest to ważne, jeśli na przykład wyrażenie jest wywołaniem metody z efektami ubocznymi. (Podziękowania dla @Joey za zwrócenie na to uwagi.)
??
jest skojarzony, więc a ?? b ?? c ?? d
jest równoważny z ((a ?? b) ?? c ) ?? d
. „Operatory przypisania i operator trójskładnikowy (? :) są prawymi asocjacjami. Wszystkie pozostałe operatory binarne pozostają asocjatywne”. Źródło: msdn.microsoft.com/en-us/library/ms173145.aspx
Tylko dlatego, że nikt inny nie wypowiedział jeszcze magicznych słów: to zerowy operator koalescencyjny . Jest zdefiniowany w sekcji 7.12 specyfikacji języka C # 3.0 .
Jest bardzo przydatny, szczególnie ze względu na sposób działania, gdy jest używany wielokrotnie w wyrażeniu. Wyrażenie formy:
a ?? b ?? c ?? d
poda wynik wyrażenia, a
jeśli nie ma wartości null, w przeciwnym razie spróbuj b
, w przeciwnym razie spróbuj c
, w przeciwnym razie spróbuj d
. W każdym punkcie powoduje zwarcie.
Ponadto, jeśli typ d
nie ma wartości zerowej, typ całego wyrażenia również nie ma wartości zerowej.
To zerowy operator koalescencyjny.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
Tak, prawie niemożliwe do wyszukania, chyba że wiesz, jak się nazywa! :-)
EDYCJA: I to jest fajna funkcja z innego pytania. Możesz je połączyć.
Dziękujemy wszystkim, oto najbardziej zwięzłe wyjaśnienie, które znalazłem na stronie MSDN:
// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;
-1
jest po prostu zwykłą int
, która nie jest zerowalna).
x
jest typu int?
, ale y
jest typu int
, możesz napisać int y = (int)(x ?? -1)
. Będzie analizować x
do int
jeśli nie jest null
, lub przypisać -1
do y
jeżeli x
jest null
.
Dwa znaki zapytania (??) wskazują, że jest to operator koalescencyjny.
Operator koalescencji zwraca pierwszą wartość NON-NULL z łańcucha. Możesz obejrzeć ten film na youtube, który praktycznie pokazuje całą sprawę.
Ale pozwól mi dodać więcej do tego, co mówi film.
Jeśli widzisz angielskie znaczenie koalescencji, to mówi „konsoliduj razem”. Na przykład poniżej znajduje się prosty kod łączący cztery łańcuchy.
Więc jeśli str1
jest null
to spróbować str2
, jeśli str2
to null
będzie starał str3
i tak dalej, aż znajdzie ciąg o wartości innej niż NULL.
string final = str1 ?? str2 ?? str3 ?? str4;
Krótko mówiąc, operator koalescencyjny zwraca pierwszą wartość NON-NULL z łańcucha.
To krótka ręka dla operatora trójskładnikowego.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
Lub dla tych, którzy nie robią trójki:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
!= null
), jak i drugi formsAuth
(po ?
) mogą być zmienione; w zerowej formie koalescencji obydwa domyślnie przyjmują podane wartości.
Jeśli znasz Ruby, ||=
wydaje mi się , że jest podobny do C # ??
. Oto niektóre Ruby:
irb(main):001:0> str1 = nil
=> nil
irb(main):002:0> str1 ||= "new value"
=> "new value"
irb(main):003:0> str2 = "old value"
=> "old value"
irb(main):004:0> str2 ||= "another new value"
=> "old value"
irb(main):005:0> str1
=> "new value"
irb(main):006:0> str2
=> "old value"
I w C #:
string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";
x ||= y
sprowadza się do czegoś podobnego x = x || y
, więc w ??
rzeczywistości jest bardziej podobny do zwykłego ||
w Ruby.
??
tylko dba o null
, podczas gdy ||
operator w Ruby, jak w większości języków, to bardziej null
, false
lub coś, co można uznać za logiczną o wartości false
(na przykład w niektórych językach ""
). To nie jest ani dobra ani zła rzecz, tylko różnica.
Nie ma w tym nic niebezpiecznego. W rzeczywistości jest piękny. Możesz dodać wartość domyślną, jeśli jest to pożądane, na przykład:
KOD
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
int? x1 = null;
Czy to prawda
x1
- x4
MUSI być typami zerowalnymi: nie ma sensu mówić skutecznie: „wynikiem jest, 0
jeśli x4
jest wartością, której nie byłby w stanie przyjąć” ( null
). „Typ dopuszczający wartości zerowe” obejmuje tutaj zarówno typy dopuszczające wartości zerowe, jak i typy referencyjne. Jest to błąd czasu kompilacji, jeśli jedna lub więcej zmiennych łańcuchowych (oprócz ostatniej) nie ma wartości zerowej.
Jak słusznie wskazano w wielu odpowiedziach, że jest to „zerowy operator koalescencyjny” ( ?? ), mówiąc o którym możesz również chcieć sprawdzić jego kuzyna „zerowy operator warunkowy” ( ?. Lub ? [ ), Który jest operatorem, który wiele razy jest używany w połączeniu z ??
Służy do testowania wartości null przed wykonaniem operacji dostępu do elementu ( ?. ) Lub indeksu ( ? [ ). Te operatory pomagają pisać mniej kodu do obsługi kontroli zerowych, szczególnie w przypadku schodzenia do struktur danych.
Na przykład:
// if 'customers' or 'Order' property or 'Price' property is null,
// dollarAmount will be 0
// otherwise dollarAmount will be equal to 'customers.Order.Price'
int dollarAmount = customers?.Order?.Price ?? 0;
stary sposób bez ? i ?? robienia tego jest
int dollarAmount = customers != null
&& customers.Order!=null
&& customers.Order.Price!=null
? customers.Order.Price : 0;
co jest bardziej pełne i kłopotliwe.
Tylko dla twojej rozrywki (wiedząc, że wszyscy jesteście facetami z C # ;-).
Myślę, że powstał w Smalltalk, gdzie istnieje od wielu lat. Jest tam zdefiniowany jako:
w obiekcie:
? anArgument
^ self
w UndefinedObject (aka nil's class):
? anArgument
^ anArgument
Istnieją zarówno wersje oceniające (?), Jak i nieoceniające (??) tego.
Często można go znaleźć w metodach pobierających zmienne prywatne (instancja) zainicjowane z opóźnieniem, które są zerowe, dopóki nie są naprawdę potrzebne.
Niektóre przykłady uzyskiwania wartości przy użyciu koalescencji są nieefektywne.
Naprawdę chcesz:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
lub
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Zapobiega to odtwarzaniu obiektu za każdym razem. Zamiast zmiennej prywatnej pozostającej pustej i przy każdym żądaniu tworzony jest nowy obiekt, zapewnia to przypisanie zmiennej prywatnej, jeśli nowy obiekt zostanie utworzony.
??
skrót nie jest oceniany? new FormsAuthenticationWrapper();
jest oceniany wtedy i tylko wtedy, gdy _formsAuthWrapper
jest zerowy.
Przeczytałem cały ten wątek i wiele innych, ale nie mogę znaleźć tak dokładnej odpowiedzi, jak to jest.
Przez co całkowicie zrozumiałem „dlaczego używać? I kiedy używać? I jak korzystać?”.
Fundacja komunikacji Windows uwolniona przez Craiga McMurtry'ego ISBN 0-672-32948-4
Istnieją dwie typowe okoliczności, w których chciałoby się dowiedzieć, czy wartość została przypisana do instancji typu wartości. Po pierwsze, instancja reprezentuje wartość w bazie danych. W takim przypadku chcielibyśmy mieć możliwość zbadania instancji w celu ustalenia, czy wartość rzeczywiście znajduje się w bazie danych. Inną okolicznością, bardziej związaną z przedmiotem tej książki, jest sytuacja, gdy instancja reprezentuje element danych otrzymany z jakiegoś zdalnego źródła. Ponownie chciałoby się ustalić z instancji, czy otrzymano wartość dla tego elementu danych.
.NET Framework 2.0 zawiera ogólną definicję typu, która zapewnia przypadki takie jak te, w których chce się przypisać wartość null do instancji typu wartości i przetestować, czy wartość instancji jest pusta. Ta ogólna definicja typu to System.Nullable, która ogranicza ogólne argumenty typu, które mogą być zastąpione T dla typów wartości. Instancjom typów zbudowanych z System.Nullable można przypisać wartość null; w rzeczywistości ich wartości są domyślnie zerowe. Zatem typy skonstruowane z System.Nullable można nazwać typami wartości zerowalnych. System.Nullable ma właściwość Value, dzięki której można przypisać wartość przypisaną do instancji typu zbudowanego na jej podstawie, jeśli wartość instancji nie jest równa null. Dlatego można napisać:
System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}
Język programowania C # zapewnia skróconą składnię do deklarowania typów zbudowanych z System.Nullable. Ta składnia pozwala na skrócenie:
System.Nullable<int> myNullableInteger;
do
int? myNullableInteger;
Kompilator zapobiegnie próbie przypisania wartości typu wartości zerowej do zwykłego typu wartości w następujący sposób:
int? myNullableInteger = null;
int myInteger = myNullableInteger;
Uniemożliwia to zrobienie tego, ponieważ dopuszczalny typ wartości może mieć wartość null, co w rzeczywistości miałby w tym przypadku, a tej wartości nie można przypisać do zwykłego typu wartości. Chociaż kompilator zezwala na ten kod,
int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;
Druga instrukcja spowodowałaby zgłoszenie wyjątku, ponieważ każda próba dostępu do właściwości System.Nullable.Value jest niepoprawną operacją, jeśli typowi zbudowanemu z System.Nullable nie przypisano prawidłowej wartości T, co nie miało miejsca w tym przypadku walizka.
Jednym z prawidłowych sposobów przypisania wartości typu zerowalnego wartości do zwykłego typu wartości jest użycie właściwości System.Nullable.HasValue w celu ustalenia, czy do typu wartości dopuszczalnej zerowej została przypisana poprawna wartość T:
int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}
Inną opcją jest użycie tej składni:
int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;
Przez co zwykła liczba całkowita myInteger jest przypisywana wartości zerowalnej liczby całkowitej „myNullableInteger”, jeśli ta ostatnia ma przypisaną prawidłową wartość całkowitą; w przeciwnym razie myInteger zostanie przypisana wartość -1.
Jest zerowym operatorem koalescencyjnym, który działa podobnie do operatora trójskładnikowego.
a ?? b => a !=null ? a : b
Innym interesującym punktem tego jest: „Typ zerowalny może zawierać wartość lub może być niezdefiniowany” . Jeśli więc spróbujesz przypisać typ wartości dopuszczającej wartości zerowe do typu wartości nie dopuszczającej wartości zerowej, otrzymasz błąd czasu kompilacji.
int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.
Więc zrobić to za pomocą? operator:
z = x ?? 1; // with ?? operator there are no issues
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
jest równa
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
Ale fajną rzeczą jest to, że możesz je połączyć, jak mówili inni ludzie. Jedyną nie poruszoną kwestią jest to, że można go użyć do zgłoszenia wyjątku.
A = A ?? B ?? throw new Exception("A and B are both NULL");
??
Operatora nazywana jest operator null koalescencji. Zwraca operand po lewej stronie, jeśli operand nie jest pusty; w przeciwnym razie zwraca operand po prawej stronie.
int? variable1 = null;
int variable2 = variable1 ?? 100;
Ustaw variable2
na wartość variable1
, jeśli variable1
NIE jest pusta; w przeciwnym razie variable1 == null
, ustaw variable2
na 100.
Inni opisali Null Coalescing Operator
całkiem dobrze. Dla zainteresowanych istnieje skrócona składnia, w której to (pytanie SO):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
jest równoważne z tym:
FormsAuth ??= new FormsAuthenticationWrapper();
Niektórzy uważają to za bardziej czytelne i zwięzłe.