zurück zum Artikel

Neues zu Roslyn und C#

Dr. Fabian Deitelhoff

Lange Zeit wurde spekuliert, ob auf der BUILD-Konferenz 2014, eine neue Version on C# vorgestellt wird. Das ist nicht passiert. Microsoft schenkte stattdessen einem anderen Projekt viel Aufmerksamkeit: Roslyn.

Neues zu Roslyn und C#

Lange Zeit wurde spekuliert, ob auf der BUILD-Konferenz 2014, eine neue Version on C# vorgestellt wird. Das ist nicht passiert. Microsoft schenkte stattdessen einem anderen Projekt viel Aufmerksamkeit: Roslyn.

Roslyn geistert schon seit 2010 durch die .NET Community. Seit dem machte das Projekt mit immer neuen Gerüchten und Prognosen auf sich aufmerksam. An eine Veröffentlichung haben viele nicht mehr geglaubt, da Microsoft den Termin immer wieder verschob.

Streng genommen wurde das Projekt bis heute nicht richtig veröffentlicht. Es steht lediglich eine weitere Vorabversion zur Verfügung. Letztere bietet, anders als die Versionen zuvor, aber nicht nur einen Einblick in die aktuellen Features der Compiler-Plattform: Roslyn implementiert in der momentanen Vorschauvariante neue Funktionen der Programmiersprachen C# und Visual Basic.NET. Für interessierte Anwender und Anwenderinnen ist die aktualisierte Preview also die Gelegenheit, Neues auszuprobieren.

Zur Erinnerung: Mit Roslyn steht nicht nur ein typischer Batch Compiler für C# und Visual Basic.NET zur Verfügung, bei dem man vorn etwas Code eingibt und am Ende eine Zwischensprache herauskommt. Roslyn bietet zusätzlich ein API an. Mit ihr ist der Zugriff auf die Struktur eines beliebigen C#-Quelltextes möglich – beispielsweise für das Implementieren von Analyse-Tools. Abbildung 1 zeigt eine schematische Übersicht der vorhandenen Schnittstellen und deren Aufbau.

Bestandteile und Schichten des Roslyn-Projekts (Abb. 1)

Bestandteile und Schichten des Roslyn-Projekts (Abb. 1)


Im Allgemeinen steht das Projekt Roslyn für eine neue Art von Compiler, die mit managed Code geschrieben wird. Ob sich diese Art durchsetzt, wird sich zeigen müssen. Das Echo ist bisher geteilt. Viele halten Roslyn, beziehungsweise die damit verbundene Art und Weise mit Compilern umzugehen, für eine mögliche Zukunft [1] im Bereich der Programmiersprachen. Mit ihr bieten sich jedem Entwickler deutlich weitreichendere Möglichkeiten, zum Beispiel um die Syntax anzupassen oder eine eigene Domain Specific Language (DSL) zu erstellen.

Andere fragen sich wiederum, warum es dazu ein eigenständiges Projekt braucht. Sprachen wie F# beherrschen das schon längere Zeit. Eine interessante Analyse, wie komplex Projekte wie Roslyn oder ein F#-Compiler sind, lässt sich in einem Blogeintrag [2] nachlesen.

Die neue Preview-Version des Compiler-Projekts war allerdings nicht die bedeutendste Meldung der BUILD 2014 in Bezug auf Roslyn. Wesentlich mehr Aufmerksamkeit bekam die Nachricht, dass Roslyn ab sofort Open Source ist und der gesamte Quelltext zur Verfügung steht. Anders Hejlsberg veröffentlichte live auf der Bühne das Git-Repository [3], das auf CodePlex beheimatet ist. Der interessante und sicherlich von wenigen vorhergesehene Schritt zeigt, dass Microsoft in Sachen Open-/Closed-Source lernfähig ist. Das Unternehmen kann sich nicht länger der Community verschließen. Das gilt insbesondere für die Unix-Welt, die mit Mono gezeigt hat, dass Interesse und Bedarf an C# besteht, auch wenn die darunter liegende Plattform nicht Windows heißt. Das Repository lässt sich direkt mit dem Befehl

git clone https://git01.codeplex.com/roslyn 

lokal klonen. Wichtiger Hinweis: Um das Projekt erfolgreich zu kompilieren, ist aktuell noch eine installierte Version von Roslyn notwendig. Das liegt an bestimmten Abhängigkeiten, die sich sonst nicht auflösen lassen. Nähere Informationen dazu bietet die Dokumentation [4] auf CodePlex.

Als Lizenz kommt die Apache License in Version 2.0 zum Einsatz. Auch das ist sehr erfreulich, da es sich um eine wirkliche "Änderungen erwünscht"-Lizenz handelt und nicht um eine "nur gucken, nicht anfassen"-Lizenz, die in den vergangenen Jahren häufiger bei Microsoft-Projekten zum Einsatz kam.

Bevor die neuen Funktionen zur Verfügung stehen, ist die aktuelle Preview-Version des Roslyn-Projekts auf dem Rechner zu installieren. Das lässt sich beispielsweise über Microsofts Download-Bereich [5]realisieren. Dort sind diverse Downloads zu Visual Studio und dem .NET Framework zu finden. Ist der Filter auf ".NET Compiler Platform" eingestellt, tauchen nur noch zwei Downloads auf. Beide Male handelt es sich um die ".NET Compiler Platform (Roslyn) SDK Preview", nur in unterschiedlichen Versionen. Eine ist in der aktuellen Community Technology Preview (CTP) von Visual Studio 2014 enthalten. Der andere Download gilt Visual Studio 2013, auf dessen Grundlage auch der vorliegende Artikel und seine Beispiele entstanden sind.

Für die Downloads ist ein Microsoft Live Account notwendig. Zudem erscheint nach dem Einloggen eine kurze Umfrage. Microsoft begründet das damit, dass das Unternehmen auf Feedback der Community angewiesen ist, um Roslyn zur verbessern.

An dieser Stelle noch ein kleiner Hinweis: Häufig macht eine veraltete Version des NuGet-Paket-Managers bei der Installation der Roslyn-Vorabversion Probleme. Er muss mindestens in Version 2.8.1 oder höher vorliegen. Es schadet daher sicherlich nicht, vor dem Einrichten von Roslyn in Visual Studio im Menü unter "Tools" > "Extensions and Updates" nachzuschauen, welche Version installiert und ob ein Update vorhanden ist.

Die Downloads enthalten vsix-Pakete, mit denen sich Visual Studio um die zusätzlichen Funktionen erweitern lässt. Wer nur die End User Preview von Roslyn ausprobieren möchte, muss lediglich die Datei Roslyn End User Preview.vsix installieren. Ansonsten stehen noch die Projekt-Templates und der Syntax Visualizer zur Verfügung. Nach der Installation ist ein Neustart von Visual Studio erforderlich, im Anschluss stehen alle Sprachfeatures und APIs zur Verfügung.

Neben vielen Beispielen in Form von C#- und Visual Basic.NET-Code, liefert die aktualisierte Roslyn-Preview auch einige Tools mit. Sie sollen zeigen, was Roslyn ermöglicht und integrieren sich teilweise direkt in Visual Studio.

Besonders hilfreich ist etwa der Syntax Visualizer. Das Werkzeug ermöglicht die Inspektion beliebigen C#- und Visual-Basic.NET-Codes, der innerhalb von Visual Studio geöffnet ist. Das Tool ist direkt in Visual Studio integriert und lässt sich über View > Other Windows > Roslyn Syntax Visualizer aufrufen. Abbildung 2 zeigt es in Aktion.

Die zwei Bereiche des Syntax Visualizer (Abb. 2)

Die zwei Bereiche des Syntax Visualizer (Abb. 2)

Im oberen Bereich ist der Syntaxbaum zu sehen. Der untere zeigt die Eigenschaften des angeklickten Elements an. Das verdeutlicht die Art und Weise, wie Roslyn Quelltext erkennt und verarbeitet, was den Syntax Visualizer zu einem unverzichtbaren Werkzeug macht, wenn selbst an oder mit Roslyn entwickelt werden soll.

Ein noch genaueres Bild vom Aufbau bietet ein sogenanntes Syntaxdiagramm. Ist im Code ein Bereich markiert, hebt der Visualizer die entsprechende Definition hervor. Über den Knoten lässt sich das Syntaxdiagramm mit der rechten Maustaste und dem Kontextmenüeintrag "View Directed Syntax Graph" aufrufen. Abbildung 3 zeigt als Beispiel ein Diagramm für eine statische Main-Methode. Beide der vorgestellten Features funktionieren für C# und Visual Basic.NET. Die weiteren Funktionen des Syntax Visualizers sind detailliert in der Dokumentation zu Roslyn auf CodePlex beschrieben.

Directed Syntax Graph eines C#-Code-Ausschnitts (Abb. 3)

Directed Syntax Graph eines C#-Code-Ausschnitts (Abb. 3)

Darüber hinaus steht beispielsweise noch der sogenannte Syntax Quoter [6] zur Verfügung. Es handelt sich dabei um eine Webseite, die C#- und Visual-Basic-.NET-Code entgegennimmt. Auf Knopfdruck analyisiert sie Letzteren und zerlegt ihn in seine Struktur. Sie dient im Anschluss als Grundlage für das Erzeugen von Anweisungen, die von der Roslyn-API Gebrauch machen, um den vom Benutzer eingegeben Code zu reproduzieren. Das erleichtert es Entwicklern enorm, eigene Quelltexte durch die Roslyn-API zu erzeugen, da die dafür erforderlichen Aufrufe nicht mehr manuell Anweisung für Anweisung einzugeben sind.

Damit reiht sich das Tool in die Riege der Werkzeuge für die Entwickler ein, die Roslyn erweitern oder damit weitere Werkzeuge erstellen möchten. Abbildung 4 enthält den erzeugen Quelltext für das Beispiel

var message = "Hallo";

Die Webseite kommt zwar auch mit deutlich komplexeren Beispielen zurecht, allerdings sprengen die erzeugten API-Aufrufe schnell den Platz für eine Abbildung.

Syntax Quoter hilft beim automatischen Erzeugen von API-Aufrufen. (Abb. 4)

Syntax Quoter hilft beim automatischen Erzeugen von API-Aufrufen. (Abb. 4)

Zu guter Letzt sei noch der Verweis auf die online verfügbaren Quellen [7] des Roslyn-Code erlaubt. Sie zeigen eindrucksvoll, was mit dem Compiler möglich ist. Die Live-Ansicht des Quelltextes ist ebenfalls mit Roslyn implementiert und steht für eigene Projekte zur Verfügung. Neben dem eigentlichen Roslyn-Code wurden auch die allgemeinen Referenzen [8] der .NET-Plattform überarbeitet. Sie sind, dank Roslyn, deutlich einfacher zu navigieren.

Neben den vorgestellten Tools und den allgemeinen Möglichkeiten, die mit Roslyn zur Verfügung stehen, gibt es einen weiteren wichtigen Grund, sich mit der aktuellen Preview zu beschäftigen. Insbesondere für Entwickler, die nicht direkt an den Compiler-Funktionen des Projekts interessiert sind, sind die enthaltenen neuen Sprachfunktionen womöglich sogar die wichtigste Neuerung überhaupt.

Was unlängst als C# 6.0 bezeichnet wird, sind neue Sprach-Features von C#, die nur über Roslyn zur Verfügung stehen und sich auf keinem anderen Weg ausprobieren lassen. Tabelle 1 fasst wichtige C#-Versionen der Geschichte zusammen und listet einige entscheidende Sprachelemente auf, die in ihnen eingeführt wurden.

C#-Version .NET-Version Jahr Sprachelemente
2.0 2.0/3.0 2005 Generics, Iteratoren, Nullable-Datentyp, Kovarianz und Kontravarianz, Delegaten
3.0 3.5 2007 Implizit typisierte Variablen, Erweiterungsmethoden, Lambda-Ausdrücke, LINQ, Objekt- und Collection-Initialisierer
4.0 4.0 2010 Dynamische Bindung, optionale und benannte Agumente, generische Kovarianz und Kontravarianz

Tabelle 1: Einige wichtige Versionen von .NET und C#.

Recht offensichtlich ist, dass es sich bei den neuen Sprachfunktionen meist um syntaktischen Zucker handelt. Bis auf einige Ausnahmen vereinfacht die neue Version nur Dinge, die bisher schon mit C# möglich waren. Große Umbrüche oder gar ein neues Sprachdesign lassen sich nicht finden. C# 6.0 setzt deutlich auf Komfort und nähert sich in Fragen des syntaktischen Aufbaus anderen Sprachen.

Eigenschaften oder Properties werden in C# gerne genutzt und lösen die Kombination aus Getter/Setter und privaten Feldern ab. Sogenannte "auto-properties" lassen sich sogar ganz ohne private Felder definieren. Der C#-Compiler erzeugt sie automatisch und wird dies in der kommenden Version auf für Properties tun. Der folgende Codeausschnitt zeigt dazu zwei Beispiele.

public class Customer
{
public string Firstname { get; set; } = "Fabian";
public string Lastname { get; set; } = "Deitelhoff";
}

public class Customer
{
public string Firstname { get; } = "Fabian";
public string Lastname { get; } = "Deitelhoff";
}

In der oberen Klasse werden zwei "auto-property"-Objekte direkt mit zwei Zeichenketten initialisiert. Da die Initialisierung nun möglich ist, fällt es deutlich einfacher, eine Klasse vollständig als immutable zu definieren. Früher ging das nur mit Read-only-Feldern und privaten Settern, wobei bei letzteren Properties über einen Konstruktor zu setzen waren. In beiden Fällen war allerdings mehr notwendig als die reine Property, sodass der Vorteil etwas gemindert wurde. Mit einer "getter-only"-Property und direkter Initialisierung ist das nun einfacher zu erreichen, was viel Code einsparen kann.

Das nächste Sprachfeature adressiert den Umstand, dass Konstruktoren, die Parameter für Eigenschaften enthalten, innerhalb einer Klasse zu deklarieren sind. Das folgende Beispiel zeigt dazu eine Klasse mit einem primären Konstruktor:

public class Customer(string firstName, string lastName)
{
public string Firstname { get; } = firstName;
public string Lastname { get; } = lastName;
}

Die Klassendefinition bekommt direkt beide Parameter mitgegeben, die wiederum bei der Initialisierung der beiden "auto-properties" zum Einsatz kommen. Der gleiche Effekt lässt sich bisher nur über zwei private Felder realisieren, denen Entwickler die Parameter eines eigens definierten Konstruktors übergeben können. Ein Knackpunkt dieses Beispiels sind die beiden Eigenschaften, die keinen Setter enthalten. Neben den Settern lassen sich auch die privaten Felder einsparen. Wie Eingangs erwähnt, ist das lediglich eine Verbesserung der Syntax.

Im übrigen funktioniert das neue Verhalten auch mit privaten Feldern, die man direkt in der Klassendefinition mit angeben kann:

public class Customer(string firstName, string lastName, 
private int age)
{
public string Firstname { get; } = firstName;
public string Lastname { get; } = lastName;
}

Das private Feld age kann in der Klasse Customer an beliebigen Stellen zum Einsatz kommen.

Die nächste Funktion ist, aus Sicht des Schreib- und Leseaufwands, sicherlich zu begrüßen, dennoch ist sie nicht unumstritten: Es geht um den Einsatz von statischen Klassen beziehungsweise deren statischen Methoden und die Verwendung von using-Anweisungen. Im folgenden ist ein typischer Code-Ausschnitt zu sehen.

using System.Console;
using System.Math;

private class Program
{
static void Main()
{
WriteLine(Pow(2, 4));
}
}

Mit ihm soll das Programm das Ergebnis von 2 hoch 4 berechnen und es im Anschluss direkt auf der Konsole ausgeben. Allerdings fehlen hier ganz offensichtlich die using-Anweisungen. Die Namensräume System.Console und System.Math werden direkt zu Anfang eingebunden. Das neue Sprachfeature sorgt dafür, dass alle statischen Member im Code ohne explizite Nennung des jeweiligen Namensraums zur Verfügung stehen. Das hört sich im ersten Moment vielleicht vorteilhaft an. Wird das Feature allerdings zu oft genutzt, insbesondere bei verschachtelten Aufrufen, kann es auch enorm dazu beitragen, dass unleserlicher Code entsteht. Das hat auch Microsoft erkannt und im aktuellen Dokument "Upcoming Features in CSharp" darauf hingewiesen.

Selbiges gilt für Erweiterungsmethoden, die bekanntlich nichts anders als statische Methoden sind – obwohl ihre Erfinder sie nicht dazu konzipierten, dass man sie wie solche nutzt. Hier wird es in zukünftigen Versionen von Roslyn Änderungen geben.

Die Option, Deklarationen direkt in Anweisungen durchführen zu können, ist eine sehr kleine Änderung in C#. Nichtsdestotrotz kann sie Code deutlich reduzieren – nicht unbedingt pro Anweisung, aber häufig macht es in dem Fall die Masse, wie der folgende Ausschnitt zeigt:

if (int.TryParse(s, out int index))
GetData(out var min, out var max);
Console.WriteLine("Ziel: {0}", (int target = CalculateTarget()) * distance);

Allen Fällen ist gemein, dass sich Variablen direkt innerhalb einer Methode beziehungsweise in der Anweisung deklarieren lassen. Bisher war es zwingend erforderlich, das schon vorher zu tun.

An Stellen, an denen var zum Einsatz kommt, wird der Typ durch Deklarationen ermittelt. Dazu dient beispielsweise eine Methodensignatur, in der out-Parameter eines bestimmten Typs vorhanden sind. Auch hier stellt sich die Frage, ob die Funktion das Ziel des Quelltextes verschleiert. Der übermäßige Einsatz des Features sollte daher wohl bedacht werden.

Mit Filtern für Exceptions erhält C# endlich eine Funktion, die schon aus Visual Basic.NET und F# bekannt ist (siehe folgender Codeauszug).

try 
{
...
}
catch (Exception e) if (CheckStatus(e))
{
...
}

Nur wenn die Methode CheckStatus true zurückliefert, führt das Programm den Catch-Block aus. Andernfalls wird die Exception einfach eine Ausführungsebene nach oben gereicht – so, als wenn es den Block gar nicht gäbe.

Ein Vorteil solch eines Vorgehens ist, dass dadurch der Stacktrace im ursprünglichen Zustand verbleibt. Anders, als wenn der Catch-Block immer aktiv ist und im Zweifel die Exception über das Schlüsselwort throw erneut geworfen wird.

Die letzte Neuerung betrifft das Schüsselwort await, das nun in finally- und catch-Blöcken erlaubt ist. Bisher war das nicht der Fall, da Microsoft laut eigener Begründung bisher nicht wusste, wie sich das Feature implementieren lässt. Offensichtlich hat sich das geändert, wie der Ausschnitt zeigt:

string result = null;

try
{
result = await CalculateResultAsync();
...
}
catch(CalculateResultException e)
{
await Log.WriteAsync(e);
}
finally
{
if (result != null)
{
await WriteResultAsync(result);
}
}

Auch mit C# 5.0 eingeführte Funktionen rund um async und await können, dank Roslyn, nun in finally und catch zum Einsatz kommen. Das macht einige unschöne Workarounds während der Entwicklung unnötig.

Aber wer profitiert nun von Roslyn im Allgemeinen und den Neuerungen in C# im Konkreten? Zum einen sind es Entwickler, die jeden Tag mit der Sprache und der Entwicklungsumgebung Visual Studio zu tun haben. Durch neue Features können Vereinfachungen Einzug in C# halten, wobei selbiges für Fehlerkorrekturen und sonstige Verbesserungen gilt.

Ganz allgemein hat Microsoft vor, neue Versionen von Roslyn, C# und dadurch auch von Visual Studio schneller auf den Markt zu bringen. Microsoft hat wohl gemerkt, dass es in der heutigen Zeit nicht mehr möglich ist, sich jahrelang einzuschließen, um danach mit einer neuen Produktpalette aufzuwarten. Kunden lassen sich nicht gerne vor vollendete Tatsachen stellen, sondern möchten gerne Einfluss auf die Entwicklung nehmen. Ob das gelingt und wie gut der schnellere Produktzyklus angenommen wird, muss sich zeigen.

Roslyn-Entwicklern, die mehr für C# implementieren möchten, etwa Werkzeuge zur Code-Analyse, bieten sich durch die umgesetzten Maßnahmen ebenfalls Vorteile. Durch die Neugestaltung des Compilers in Module lassen sich letztere separat in eigene Projekte übernehmen. Dafür steht unter anderem das NuGet-Paket Microsoft.CodeAnalysis zur Verfügung. Die darin enthaltenen Komponenten sind zudem über eigene Pakete einzeln verfügbar. Auch Scripting und eine bessere Code-Generierung lassen sich so umsetzen.

Letztlich profitiert auch die Community rund um C#. Auf der BUILD 2014 präsentierten Miguel de Icaza und Anders Hejlsberg Roslyn beziehungsweise C# auf Mono. Und zwar keine ältere Version, sondern exakt die, die kurz zuvor unter Windows als Beispiel diente. Das bedeutet, dass es in Zukunft vermutlich eine bessere und breitere Unterstützung für Unix-Systeme geben wird. Nicht zuletzt ist dadurch Visual Basic.NET auf Mono möglich.

Bei Roslyn handelt es sich zweifelsohne um eine weitere Community Technology Preview (CTP), die Entwickler auf Herz und Nieren prüfen sollten. Ein produktiver Einsatz ist daher zunächst nicht zu empfehlen. Zudem sind noch nicht alle gewünschten Funktionen implementiert. Tabelle 2 enthält dazu eine kleine Übersicht aus Sicht von C#, die zeigt, welche Funktionen bereits vorhanden und welche für zukünftige Releases geplant sind. Eine vollständige Liste, die auch Visual Basic.NET betrachtet, befindet sich in der Dokumentation auf CodePlex [9].

Feature Beispiel Status C#
Primary constructors class Point(int x, int y) { … } Done
Auto-property initializers public int X { get; set; } = x; Done
Getter-only auto-properties public int Y { get; } = y; Done
Using static member using System.Console; … Write(4); Done
Dictionary initializer new JObject { ["x"] = 3, ["y"] = 7 } Done
Indexed member initializer new JObject { $x = 3, $y = 7 } Withdrawn
Indexed member access c.$name = c.$first + " " + c.$last; Withdrawn
Declaration expressions int.TryParse(s, out var x); Done
Await in catch/finally try … catch { await … } finally { await … } Done
Exception filters catch(E e) if (e.Count > 5) { … } Done
Binary literals 0b00000100 Planned
Digit separators 0xEF_FF_00_A0 Planned

Tabelle 2: Übersicht über bereits implementierte und geplante Funktionen der aktuellen Roslyn-Version.

Das Projekt Roslyn hat schon einige Entwicklungszeit auf dem Buckel. So langsam lässt sich aber erahnen, in welche Richtung es geht und was Entwicklern bevorsteht, die mit C# beziehungsweise Visual Basic .NET arbeiten.

Ob das alles nur positive Auswirkungen hat, muss sich erst noch zeigen. Die Zeichen stehen aber gut, dass die Entwicklung von C# und Visual Studio jetzt etwas dynamischer und flexibler, ja vielleicht agiler vonstattengeht. C# als Sprache und .NET als Plattform ist es zu wünschen.

Fabian Deitelhoff [10] (@FDeitelhoff [11])
lebt und arbeitet in Dortmund. Er ist als freier Autor, Pluralsight-Autor, Sprecher und Softwareentwickler im .NET Umfeld tätig.
(jul [12])


URL dieses Artikels:
https://www.heise.de/-2292919

Links in diesem Artikel:
[1] http://blog.simontimms.com/2014/04/04/roslyn-changes-everything/
[2] http://fsharpforfunandprofit.com/posts/roslyn-vs-fsharp-compiler/
[3] https://roslyn.codeplex.com
[4] https://roslyn.codeplex.com/documentation
[5] https://connect.microsoft.com/VisualStudio/Downloads
[6] http://roslynquoter.azurewebsites.net/
[7] http://source.roslyn.codeplex.com/
[8] http://referencesource.microsoft.com/
[9] https://roslyn.codeplex.com/documentation
[10] http://www.fabiandeitelhoff.de
[11] https://twitter.com/FDeitelhoff
[12] mailto:jul@heise.de