O que o operador de ponto de interrogação e ponto? significa em C # 6.0?

359

Com o C # 6.0 na visualização do VS2015, temos um novo operador ?., que pode ser usado assim:

public class A {
   string PropertyOfA { get; set; }
}

...

var a = new A();
var foo = "bar";
if(a?.PropertyOfA != foo) {
   //somecode
}

o que exatamente isto faz?

Landeeyo
fonte

Respostas:

500

É 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 afor null, a?.PropertyOfAavaliará em nullvez de lançar uma exceção - ela comparará essa nullreferência com foo(usando a ==sobrecarga de string ), descobrirá que elas não são iguais e a execução entrará no corpo da ifinstruçã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
Jon Skeet
fonte
8
Não é chamado de operador condicional nulo ?
SLaks
11
@ Slaks: Eu pensei que era "nulo condicional", mas eu poderia estar errado. Na última vez em que verifiquei os documentos de recursos do idioma Roslyn, ele também não havia sido renomeado. Talvez a fonte seja a autoridade aqui - verifique.
Jon Skeet
3
@ Slaks: Claro. Em SyntaxKind é aparentemente ConditionalAccessExpression que é irritantemente nenhum deles ...
Jon Skeet
12
preferi o nome "Elvis" operator: P
Ahmed ilyas
3
Só para constar, vi cinco nomes diferentes para esse operador: navegação segura, condicional nulo, propagação nula, acesso condicional, Elvis.
Gigi
81

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);

Exemplo do DotNetFiddle :

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

Erik Philips
fonte
27
Para salvar as pessoas procurando o que o ?? é .. É o operador de coalescência nula e retornará Name se não for nulo; caso contrário, retornará "N / A".
Steve
6
@Erik Philips Eu acho que você precisa adicionar || Model.Model2.Model3.Model4.Name == null a ter a mesma lógica, caso contrário, no caso Model.Model2.Model3.Model4.Nameé null, mapped.Namevai ficarnull
RazvanR
2
@ErikPhilips Não estou na mesma página, eu acho. Por favor, tente ver o que acontece nos dois casos, se Model.Model2.Model3.Model4.Namefor null.
precisa saber é o seguinte
11
O resultado é "N / A", novamente LEIA O PRIMEIRO COMENTÁRIO. Exemplo de trabalho do DotNetFiddle.Net .
Erik Philips
7
@ ErikPhilips: Isso não tem nada a ver com o primeiro comentário, pois isso não está relacionado ao seu primeiro exemplo. elseNisto 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
derM
3

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:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators

Zeeshan Adil
fonte