Zum Inhalt springen

C# vNext – Null Propagation

Oktober 20, 2014

Im letzten Blog Post habe ich Primary Constructors und Property Initializers gezeigt. Primary Constructors werden jetzt doch nicht in C# 6 kommen – aber dafür ist es möglich Property Initializers vom Constructor Body zu initialisieren. Mehr dazu aber in einem späteren Blog Post wenn dieses Feature auch im Visual Studio zur Verfügung steht.

In diesem Blog Post möchte ich ein besonders cooles Feature von C# 6 zeigen: Null Propagation. Programmcode besteht aus vielen Zeilen null checks – genau dieser Code kann damit vereinfacht werden.

Sharp right

© Liquidphoto | Dreamstime.comSharp Right Turn Sign Photo

Falls bei einem Aufruf von obj.Foo() die Variable obj auf null zeigt, gibt es eine NullReferenceException. Deshalb sollte die Variable vorher auf null überprüft werden. Bestehender Code

if (obj != null)
{
  obj.Foo();
}

Kann einfach mit Hilfe des ?. Operators vereinfacht werden:

obj?.Foo();

Wenn obj null ist ist das Ergebnis der Expression null, ansonsten wird die Foo Methode aufgerufen. Eine simple Vereinfachung vom Code.

Doch wo und wie ist das wirklich im Einsatz? Anhand von Template-generierten C# Code in einer Windows Store App möchte ich hier ein paar Beispiele zeigen.

In der Methode GoBack der Klasse NavigationHelper findet sich dieser Syntax. Erst nach der Überprüfung von this.Frame kann auf die Property CanGoBack zugegriffen werden. Wenn diese Property true zurückliefert kann die GoBack Methode vom Frame aufgerufen werden.

    public virtual void GoBack()
    {
      if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
    }

Mit dem neuen Syntax sieht das wie folgend aus. Statt dem Extra Vergleich auf nicht null genügt ein ?. und dann ein Vergleich mit true. Das Ergebnis der Expression this.Frame?.CanGoBack kann natürlich auch null zurückliefern, deshalb ist der Vergleich mit true erforderlich.

   public virtual void GoBack()
    {
      if (this.Frame?.CanGoBack == true) this.Frame.GoBack();
    }

In der Klasse NavigationHelper findet sich auch dieser Code für die GoBackCommand Property:

public RelayCommand GoBackCommand
{
  get
  {
    if (_goBackCommand == null)
    {
      _goBackCommand = new RelayCommand(
        () => this.GoBack(),
        () => this.CanGoBack());
    }
    return _goBackCommand;
  }
  set
  {
    _goBackCommand = value;
  }
}

Auch das lässt sich vereinfachen – allerdings mit dem coalescing Operator, und das ist jetzt schon mit C# möglich. Wenn _goBackCommand nicht null ist, wird der Wert dieser Variable zurückgeliefert. Ansonsten wird ein neuer RelayCommand instanziert, und die neu gesetzte Variable _goBackCommand ist das Ergebnis des get Accessors.

public RelayCommand GoBackCommand
{
  get
  {
    return _goBackCommand ??
      (_goBackCommand = new RelayCommand(
        () => this.GoBack(),
        () => this.CanGoBack()));
  }
  set
  {
    _goBackCommand = value;
  }
}

Ganz ähnlich wie die GoBack Methode ist die CanGoBack Methode implementiert. Zuerst die Überprüfung ob Frame nicht null ist bevor das Ergebnis von CanGoBack zurückgeliefert wird.

    public virtual bool CanGoBack()
    {
      return this.Frame != null && this.Frame.CanGoBack;
    }

Der coalescing Operator ist auch im Zusammenspiel mit null propagation sehr praktisch. Wenn das Ergebnis der vorherigen Expression null ist, wird in diesem Fall false zurückgeliefert. True gibt es nur wenn Frame nicht null ist, und CanGoBack auch true zurück liefert. Mit Hilfe von Expression Bodied Members => kann diese Methode ohne geschwungene Klammern implementiert werden, mit Syntax wie wir ihn von Lambda Expressions kennen.

    public virtual bool CanGoBack() => 
      this.Frame?.CanGoBack ?? false;

Ein weiteres praktisches Beispiel findet sich in der RelayCommand Klasse. In einer thread-safe Variante zum Feuern eines Events kommt der Delegate in eine Zwischenvariable (handler), bevor der Event über den Delegate gefeuert werden kann.

public void RaiseCanExecuteChanged()
{
  var handler = CanExecuteChanged;
  if (handler != null)
  {
    handler(this, EventArgs.Empty);
  }
}

Mit null Propagation wird dieser Code sehr viel einfacher. Der direkte Aufruf der Methode nach einem ? mit ?() ist nicht möglich. Aber die Invoke Methode des Delegates bringt Abhilfe. Invoke wird nur aufgerufen wenn die linke Expression nicht null ist. Das ist auch gleich thread-safe und erspart doch einige Codezeilen.

public void RaiseCanExecuteChanged() =>
  CanExecuteChanged?.Invoke(this, EventArgs.Empty);

C# 6 hat keine so großen Features wie die async und await Keywords von C# 5 oder LINQ von C# 3. Aber es gibt viele kleine praktische Erweiterungen. Null Propagation gehört auf jeden Fall dazu.

Christian

CN innovation

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit deinem WordPress.com-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

%d Bloggern gefällt das: