Respostas:
É o operador condicional nulo . Significa basicamente:
"Avalie o primeiro operando; se for nulo, pare, com um resultado nulo. Caso contrário, avalie o segundo operando (como um acesso de membro do primeiro operando)."
No seu exemplo, o ponto é que, se a
for null
, a?.PropertyOfA
avaliará em null
vez de lançar uma exceção - ela comparará essa null
referência com foo
(usando a ==
sobrecarga de string ), descobrirá que elas não são iguais e a execução entrará no corpo da if
instrução .
Em outras palavras, é assim:
string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
...
}
... exceto que a
é avaliada apenas uma vez.
Observe que isso também pode alterar o tipo da expressão. Por exemplo, considere FileInfo.Length
. Essa é uma propriedade do tipo long
, mas se você a usar com o operador condicional nulo, você terminará com uma expressão do tipo long?
:
FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
Pode ser muito útil ao nivelar uma hierarquia e / ou mapear objetos. Ao invés de:
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;
}
Pode ser escrito como (a mesma lógica acima)
mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";
Exemplo de trabalho do DotNetFiddle.Net .
(o operador ?? ou coalescente de nulo é diferente do operador condicional? ou nulo ).
Também pode ser usado fora dos operadores de atribuição com Ação. Ao invés de
Action<TValue> myAction = null;
if (myAction != null)
{
myAction(TValue);
}
Pode ser simplificado para:
myAction?.Invoke(TValue);
using System;
public class Program
{
public static void Main()
{
Action<string> consoleWrite = null;
consoleWrite?.Invoke("Test 1");
consoleWrite = (s) => Console.WriteLine(s);
consoleWrite?.Invoke("Test 2");
}
}
Resultado:
Teste 2
|| Model.Model2.Model3.Model4.Name == null
a ter a mesma lógica, caso contrário, no caso Model.Model2.Model3.Model4.Name
é null
, mapped.Name
vai ficarnull
Model.Model2.Model3.Model4.Name
for null
.
else
Nisto mapped.Name = Model.Model2.Model3.Model4.Name -> mapped.Name = null
, você entraria no ramo -branch e o faria , enquanto o segundo exemplo substituiria mapped.Name = "N/A"
. Veja o DotNetFiddle editado
Isso é relativamente novo no C #, o que facilita a chamada de funções em relação aos valores nulos ou não nulos no encadeamento de métodos.
A maneira antiga de conseguir a mesma coisa era:
var functionCaller = this.member;
if (functionCaller!= null)
functionCaller.someFunction(var someParam);
e agora ficou muito mais fácil com apenas:
member?.someFunction(var someParam);
Eu recomendo fortemente que você leia aqui: