Risposte:
È l' operatore condizionale nullo . Significa sostanzialmente:
"Valuta il primo operando; se è null, stop, con risultato null. Altrimenti, valuta il secondo operando (come accesso membro del primo operando)."
Nel tuo esempio, il punto è che, se lo a
è null
, a?.PropertyOfA
valuterà null
invece di generare un'eccezione, quindi confronterà quel null
riferimento con foo
(usando il ==
sovraccarico della stringa ), scoprirà che non sono uguali e l'esecuzione andrà nel corpo if
dell'istruzione .
In altre parole, è così:
string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
...
}
... tranne che a
viene valutato solo una volta.
Nota che anche questo può cambiare il tipo di espressione. Ad esempio, considera FileInfo.Length
. Questa è una proprietà di tipo long
, ma se la usi con l'operatore condizionale null, finisci con un'espressione di tipo long?
:
FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
Può essere molto utile quando si appiattisce una gerarchia e / o si mappano oggetti. Invece di:
if (Model.Model2 == null
|| Model.Model2.Model3 == null
|| Model.Model2.Model3.Model4 == null
|| Model.Model2.Model3.Model4.Name == null)
{
mapped.Name = "N/A"
}
else
{
mapped.Name = Model.Model2.Model3.Model4.Name;
}
Può essere scritto come (stessa logica di cui sopra)
mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";
Esempio di funzionamento di DotNetFiddle.Net .
(l' operatore ?? o null-coalescing è diverso dall'operatore ? o null condizionale ).
Può anche essere utilizzato al di fuori degli operatori di assegnazione con Action. Invece di
Action<TValue> myAction = null;
if (myAction != null)
{
myAction(TValue);
}
Può essere semplificato per:
myAction?.Invoke(TValue);
utilizzando il sistema;
public class Program
{
public static void Main()
{
Action<string> consoleWrite = null;
consoleWrite?.Invoke("Test 1");
consoleWrite = (s) => Console.WriteLine(s);
consoleWrite?.Invoke("Test 2");
}
}
Risultato:
Test 2
|| Model.Model2.Model3.Model4.Name == null
per avere la stessa logica, altrimenti nel caso Model.Model2.Model3.Model4.Name
sia null
, mapped.Name
rimarrànull
Model.Model2.Model3.Model4.Name
è null
.
else
salteresti nel ramo e lo avresti mapped.Name = Model.Model2.Model3.Model4.Name -> mapped.Name = null
, mentre il tuo secondo esempio lo sostituirà mapped.Name = "N/A"
. Vedi il DotNetFiddle
Questo è relativamente nuovo in C #, il che ci rende facile chiamare le funzioni rispetto ai valori null o non null nel concatenamento del metodo.
il vecchio modo per ottenere la stessa cosa era:
var functionCaller = this.member;
if (functionCaller!= null)
functionCaller.someFunction(var someParam);
e ora è stato reso molto più semplice con solo:
member?.someFunction(var someParam);
Ti consiglio vivamente di leggerlo qui: