Ho attraversato questa riga di codice:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Che cosa significano i due punti interrogativi, è una specie di operatore ternario? È difficile cercare su Google.
Ho attraversato questa riga di codice:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Che cosa significano i due punti interrogativi, è una specie di operatore ternario? È difficile cercare su Google.
Risposte:
È l'operatore null coalescente, e abbastanza come l'operatore ternario (immediato). Vedi anche ?? Operatore - MSDN .
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
si espande in:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
che si espande ulteriormente a:
if(formsAuth != null)
FormsAuth = formsAuth;
else
FormsAuth = new FormsAuthenticationWrapper();
In inglese significa "Se ciò che è a sinistra non è nullo, usalo, altrimenti usa ciò che è a destra."
Si noti che è possibile utilizzare qualsiasi numero di questi in sequenza. La seguente istruzione assegnerà il primo non null Answer#
a Answer
(se tutte le risposte sono null, allora Answer
è null):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
Inoltre vale la pena ricordare che l'espansione sopra è concettualmente equivalente, il risultato di ogni espressione viene valutato solo una volta. Ciò è importante se ad esempio un'espressione è una chiamata di metodo con effetti collaterali. (Ringraziamo @Joey per averlo sottolineato.)
??
è associativo, quindi a ?? b ?? c ?? d
equivale a ((a ?? b) ?? c ) ?? d
. "Gli operatori di assegnazione e l'operatore ternario (? :) sono associativi di destra. Tutti gli altri operatori binari sono associativi di sinistra." Fonte: msdn.microsoft.com/en-us/library/ms173145.aspx
Solo perché nessun altro ha ancora detto le parole magiche: è l' operatore null coalescente . È definito nella sezione 7.12 della specifica del linguaggio C # 3.0 .
È molto utile, soprattutto per il modo in cui funziona quando viene usato più volte in un'espressione. Un'espressione del modulo:
a ?? b ?? c ?? d
darà il risultato dell'espressione a
se è diverso da null, altrimenti prova b
, altrimenti prova c
, altrimenti prova d
. Cortocircuita in ogni punto.
Inoltre, se il tipo di d
è non annullabile, anche il tipo dell'intera espressione è non annullabile.
È l'operatore null coalescente.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
Sì, quasi impossibile cercare se non sai come si chiama! :-)
EDIT: E questa è una caratteristica interessante di un'altra domanda. Puoi incatenarli.
Grazie a tutti, ecco la spiegazione più concisa che ho trovato sul sito MSDN:
// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;
-1
è solo un semplice int
, che è non annullabile).
x
è di tipo int?
, ma y
è di tipo int
, è possibile scrivere int y = (int)(x ?? -1)
. Analizzerà x
un int
se non lo è null
, o assegnerà -1
a y
se lo x
è null
.
I due punti interrogativi (??) indicano che si tratta di un operatore di coalescenza.
L'operatore di coalescenza restituisce il primo valore NON-NULL da una catena. Puoi vedere questo video di YouTube che dimostra praticamente tutto.
Vorrei aggiungere altro a ciò che dice il video.
Se vedi il significato inglese di coalescenza, dice "consolidare insieme". Ad esempio, di seguito è riportato un semplice codice a coalescenza che incatena quattro stringhe.
Quindi se str1
è null
proverà str2
, se str2
è null
proverà str3
e così via fino a quando non trova una stringa con un valore non nullo.
string final = str1 ?? str2 ?? str3 ?? str4;
In parole semplici, l'operatore di coalescenza restituisce il primo valore NON-NULL da una catena.
È una scorciatoia per l'operatore ternario.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
O per coloro che non fanno ternario:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
!= null
) che il secondo formsAuth
(dopo il ?
) potrebbero essere modificati; nella forma di coalescenza nulla, entrambi implicitamente assumono i valori forniti.
Se hai familiarità con Ruby, ||=
sembra simile a C # ??
per me. Ecco un po 'di rubino:
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"
E in C #:
string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";
x ||= y
desugars a qualcosa del genere x = x || y
, quindi in ??
realtà è più simile alla pianura ||
in Ruby.
??
solo si preoccupa null
, mentre l' ||
operatore in Ruby, come nella maggior parte delle lingue, è più su null
, false
o tutto ciò che può essere considerato un valore booleano con un valore di false
(ad esempio, in alcune lingue, ""
). Questa non è una cosa buona o cattiva, solo una differenza.
Niente di pericoloso al riguardo. In effetti è bellissimo. È possibile aggiungere un valore predefinito se ciò è desiderabile, ad esempio:
CODICE
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
int? x1 = null;
è giusto
x1
- x4
DEVE essere tipi nullable: non ha senso dire, in effetti, "il risultato è 0
se x4
è un valore che non può assumere" ( null
). "Tipo Nullable" qui include sia i tipi di valore annullabili sia i tipi di riferimento, ovviamente. È un errore in fase di compilazione se una o più variabili incatenate (tranne l'ultima) non è nulla.
Come indicato correttamente in numerose risposte, si tratta dell '"operatore a coalescenza nulla" ( ?? ), a proposito del quale potresti anche voler dare un'occhiata a suo cugino "Operatore a condizione nulla" ( ?. O ? [ ) Che è un operatore che molte volte è usato insieme a ??
Utilizzato per verificare la presenza di null prima di eseguire un'operazione di accesso ( ?. ) O indice ( ? [ ) Del membro . Questi operatori ti aiutano a scrivere meno codice per gestire i controlli null, in particolare per la discesa nelle strutture di dati.
Per esempio:
// 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;
alla vecchia maniera senza ? e ?? di fare questo è
int dollarAmount = customers != null
&& customers.Order!=null
&& customers.Order.Price!=null
? customers.Order.Price : 0;
che è più prolisso e ingombrante.
Solo per il tuo divertimento (sapendo che siete tutti ragazzi C # ;-).
Penso che abbia avuto origine in Smalltalk, dove esiste da molti anni. È definito lì come:
nell'oggetto:
? anArgument
^ self
in UndefinedObject (aka classe zero):
? anArgument
^ anArgument
Esistono versioni di valutazione (?) E non di valutazione (??).
Si trova spesso nei metodi getter per variabili private (istanza) inizializzate in modo pigro, che vengono lasciate nulle fino a quando non sono realmente necessarie.
Alcuni esempi qui di ottenere valori usando la coalescenza sono inefficienti.
Quello che vuoi davvero è:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
o
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Ciò impedisce di ricreare l'oggetto ogni volta. Invece che la variabile privata rimanga nulla e un nuovo oggetto venga creato su ogni richiesta, questo assicura che la variabile privata venga assegnata se viene creato il nuovo oggetto.
??
scorciatoia non viene valutata? new FormsAuthenticationWrapper();
viene valutato se e solo se _formsAuthWrapper
è nullo.
Ho letto tutto questo thread e molti altri, ma non riesco a trovare una risposta completa come questa.
Con il quale ho capito completamente il "perché usare ?? e quando usare ?? e come usare ??."
Fondazione di comunicazione Windows scatenata da Craig McMurtry ISBN 0-672-32948-4
Esistono due circostanze comuni in cui si vorrebbe sapere se un valore è stato assegnato a un'istanza di un tipo di valore. Il primo è quando l'istanza rappresenta un valore in un database. In tal caso, si vorrebbe poter esaminare l'istanza per accertare se un valore è effettivamente presente nel database. L'altra circostanza, che è più pertinente all'argomento di questo libro, è quando l'istanza rappresenta un elemento di dati ricevuto da una fonte remota. Ancora una volta, si vorrebbe determinare dall'istanza se è stato ricevuto un valore per quell'elemento dati.
.NET Framework 2.0 incorpora una definizione di tipo generico che prevede casi come questi in cui si desidera assegnare null a un'istanza di un tipo di valore e verificare se il valore dell'istanza è null. Tale definizione di tipo generico è System.Nullable, che limita gli argomenti di tipo generico che possono essere sostituiti da T a tipi di valore. Alle istanze di tipi costruite da System.Nullable può essere assegnato un valore null; in effetti, i loro valori sono nulli per impostazione predefinita. Pertanto, i tipi costruiti da System.Nullable possono essere definiti tipi di valore nullable. System.Nullable ha una proprietà, Value, in base alla quale il valore assegnato a un'istanza di un tipo costruito da essa può essere ottenuto se il valore dell'istanza non è nullo. Pertanto, si può scrivere:
System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}
Il linguaggio di programmazione C # fornisce una sintassi abbreviata per dichiarare i tipi costruiti da System.Nullable. Tale sintassi consente di abbreviare:
System.Nullable<int> myNullableInteger;
per
int? myNullableInteger;
Il compilatore impedirà a uno di tentare di assegnare il valore di un tipo di valore nullable a un tipo di valore ordinario in questo modo:
int? myNullableInteger = null;
int myInteger = myNullableInteger;
Impedisce di farlo perché il tipo di valore nullable potrebbe avere il valore null, che in realtà avrebbe in questo caso, e quel valore non può essere assegnato a un tipo di valore ordinario. Sebbene il compilatore consentirebbe questo codice,
int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;
La seconda istruzione provocherebbe il lancio di un'eccezione perché qualsiasi tentativo di accedere alla proprietà System.Nullable.Value è un'operazione non valida se al tipo costruito da System.Nullable non è stato assegnato un valore valido di T, che non è avvenuto in questo Astuccio.
Un modo corretto di assegnare il valore di un tipo di valore nullable a un tipo di valore ordinario è utilizzare la proprietà System.Nullable.HasValue per accertare se un valore valido di T è stato assegnato al tipo di valore nullable:
int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}
Un'altra opzione è utilizzare questa sintassi:
int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;
In base al quale al numero intero ordinario myInteger viene assegnato il valore del numero intero nullable "myNullableInteger" se a quest'ultimo è stato assegnato un valore intero valido; altrimenti, a myInteger viene assegnato il valore di -1.
È un operatore a coalescenza nulla che funziona in modo simile a un operatore ternario.
a ?? b => a !=null ? a : b
Un altro punto interessante per questo è: "Un tipo nullable può contenere un valore o può essere indefinito" . Pertanto, se si tenta di assegnare un tipo di valore annullabile a un tipo di valore non annullabile, verrà visualizzato un errore in fase di compilazione.
int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.
Quindi per farlo usando ?? operatore:
z = x ?? 1; // with ?? operator there are no issues
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
è equivalente a
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
Ma la cosa bella è che puoi incatenarli, come hanno detto altre persone. L'unico aspetto non toccato è che puoi effettivamente usarlo per generare un'eccezione.
A = A ?? B ?? throw new Exception("A and B are both NULL");
L' ??
operatore è chiamato operatore a coalescenza nulla. Restituisce l'operando di sinistra se l'operando non è nullo; altrimenti restituisce l'operando di destra.
int? variable1 = null;
int variable2 = variable1 ?? 100;
Impostato variable2
sul valore di variable1
, se variable1
NON è null; altrimenti, se variable1 == null
impostato variable2
su 100.
Altri hanno descritto Null Coalescing Operator
abbastanza bene. Per coloro che sono interessati, esiste una sintassi abbreviata in cui questa (la domanda SO):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
è equivalente a questo:
FormsAuth ??= new FormsAuthenticationWrapper();
Alcuni lo trovano più leggibile e succinto.