Co robi operator znaku zapytania i kropki? znaczy w C # 6.0?

359

W wersji C # 6.0 w wersji zapoznawczej VS2015 mamy nowego operatora ?., którego można użyć w następujący sposób:

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

...

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

Co to dokładnie robi?

Landeeyo
źródło

Odpowiedzi:

499

To zerowy operator warunkowy . Zasadniczo oznacza:

„Oceń pierwszy operand; jeśli jest to null, zatrzymaj z wynikiem null. W przeciwnym razie oceń drugi operand (jako dostęp członka pierwszego operandu).”

W twoim przykładzie chodzi o to, że jeśli ajest null, to zamiast a?.PropertyOfAoceny nullzgłasza wyjątek - porównuje to nullodwołanie z foo(przy użyciu ==przeciążenia łańcucha ), stwierdzi, że nie są one równe, a wykonanie przejdzie do treści ifinstrukcji .

Innymi słowy, wygląda to tak:

string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
    ...
}

... z wyjątkiem tego, że aocenia się tylko raz.

Pamiętaj, że może to również zmienić typ wyrażenia. Rozważmy na przykład FileInfo.Length. Jest to właściwość typu long, ale jeśli użyjesz jej z operatorem warunkowym o wartości NULL, otrzymasz wyrażenie typu long?:

FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
Jon Skeet
źródło
8
Czy to nie jest nazywane zerowym operatorem warunkowym ?
SLaks
1
@SLaks: Myślałem, że to „warunkowe zero”, ale mogę się mylić. Ostatnim razem, gdy sprawdzałem dokumenty dotyczące języka Roslyn, nie zmieniono jego nazwy na żadną z nich. Może źródłem jest tu władza - sprawdzi.
Jon Skeet,
3
@SLaks: Jasne. W SyntaxKind najwyraźniej jest to ConditionalAccessExpression, co irytująco nie jest żadnym z nich ...
Jon Skeet
12
Wolałem
3
Dla przypomnienia widziałem pięć różnych nazw tego operatora: bezpieczną nawigację, zerową-warunkową, zerową propagację, warunkowy dostęp, Elvis.
Gigi,
81

Może być bardzo przydatny podczas spłaszczania hierarchii i / lub mapowania obiektów. Zamiast:

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

Można to napisać jak (taka sama logika jak powyżej)

mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";

Przykład działania DotNetFiddle.Net .

( operator koalescencyjny? lub null jest inny niż operator warunkowy? lub null ).

Może być również używany po stronie operatorów przypisania za pomocą Action. Zamiast

Action<TValue> myAction = null;

if (myAction != null)
{
  myAction(TValue);
}

Można to uprościć:

myAction?.Invoke(TValue);

Przykład 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");
  }
}

Wynik:

Test 2

Erik Philips
źródło
27
Aby uratować ludzi patrząc na co? jest .. Jest operatorem zerowania koalescencji i zwraca nazwę, jeśli nie jest zerowa, w przeciwnym razie zwróci „nie dotyczy”.
Steve
6
@Erik Philips Chyba trzeba dodać || Model.Model2.Model3.Model4.Name == null mieć tę samą logikę, poza tym sprawa Model.Model2.Model3.Model4.Namejest null, mapped.Namepozostanienull
RazvanR
2
@ErikPhilips Chyba nie na tej samej stronie. Spróbuj, co się dzieje w obu przypadkach, jeśli tak Model.Model2.Model3.Model4.Namejest null.
RazvanR
1
Wynikiem jest „nie dotyczy”, ponownie PROSZĘ PRZECZYTAĆ PIERWSZY KOMENTARZ. Przykład działania DotNetFiddle.Net .
Erik Philips,
7
@ErikPhilips: To nie ma nic wspólnego z pierwszym komentarzem, ponieważ nie odnosi się to do twojego pierwszego przykładu. W ten sposób wskoczyłbyś do elseoddziału i miałbyś mapped.Name = Model.Model2.Model3.Model4.Name -> mapped.Name = null, podczas gdy drugi przykład zastąpiłby mapped.Name = "N/A". Zobacz edytowany DotNetFiddle
derM
3

Jest to stosunkowo nowe w C #, co ułatwia nam wywoływanie funkcji w odniesieniu do wartości zerowej lub innej w łańcuchu metod.

starym sposobem na osiągnięcie tego samego było:

var functionCaller = this.member;
if (functionCaller!= null)
    functionCaller.someFunction(var someParam);

a teraz stało się to znacznie łatwiejsze dzięki:

member?.someFunction(var someParam);

Zdecydowanie polecam przeczytać tutaj:

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

Zeeshan Adil
źródło