Neuerungen in Visual Studio 2008 und C# 3.5

Seit kurzem ist die finale Version der Entwicklungsumgebung Visual Studio 2008 verfügbar.

VS.NET 2008 kann zusätzlich zu VS.NET 2005 und VS.NET 2003 installiert werden. Es laufen alle drei Entwicklungsumgebungen parallel und problemlos nebeneinander auf derselben Maschine.

Visual Studio 2008

Beim Doppelklick auf ein VS.NET 2005-Projekt öffnet sich wie gewohnt VS.NET 2005. Erst wenn man ein VS.NET 2005-Projekt in VS.NET 2008 öffnet, startet automatisch der Conversion Wizard. Dieser fragt beim Wandeln nach, ob vom Framework 2.0 auf 3.5 aktualisiert werden soll, oder es bei 2.0 bleiben soll. Man kann aber auch später jederzeit auf eine Code-Erzeugung für eines der Frameworks 2.0, 3.0 oder 3.5 umstellen. Erst beim Kompilieren kann es Probleme geben, wenn man Sprachkonstrukte nutzt, die nur in einer der neueren Versionen zur Verfügung stehen.

Der erste Aufruf eines Designers (HTML, CSS, oder auch normaler Code) dauert immer noch viel zu lange. Heftige Plattenzugriffe trotz ausreichend RAM bremsen dabei das System aus. Hier könnte eine schnelle 10.000 UpM-Festplatte wie die Raptor etwas Linderung verschaffen.

Die Version 3.5 ist eigentlich keine völlig neue Version, da die zugrundeliegende Pseudo-Maschinensprache namens MSIL unverändert blieb. Die neuen Sprachkonstrukte erfordern also keinen neuen JIT-Kompiler, im wesentlichen handelt es sich um neue Bibliotheken und MSIL-Compiler. Die aus diesem Misch-Masch resultierenden Schwierigkeiten bei der Versionsermittlung beschreibt der Artikel ASP.NET Version Madness .

Zu den Neuerungen:

IntelliSense für CSS

Endlich steht IntelliSense auch in <style type="text/css">-Bereichen zur Verfügung. Dort musste man bisher remember and type beherrschen. IntelliSense in VS.NET 2005 funktionierte nur in reinen .CSS-Dateien und den style-Angaben von Tags. Das neue Feature ist gerade während der Entwicklungsphasen sehr praktisch, um schnell das Aussehen einer Webseite verändern zu können. Es müssen dafür nicht mehrere Dateien offen gehalten werden, und es gibt bei in-page-Angaben keine Probleme mit dem langen Caching von CSS-Dateien. Vollständig ist der CSS-Support aber noch nicht, IntelliSense bietet z.B. nicht das Attribut "empty-cells" an. Es gehört zwar zum Standard, aber der IE7 beherrscht es noch nicht, damit ist es für Microsoft wohl nicht existent.

In Kommentare eingebettete CSS-Befehle profitieren aber nach wie vor nicht IntelliSense:

	<!--[if lte IE 6]>
		<style type="text/css">
			#divHeader
			{
				margin-top:-8px;
			}
		</style>
	<![endif]-->

Schade, ist doch gerade diese Vorgehensweise die empfohlene für browserabhängige Anpassungen. Hier hilft nur wie bisher das Auslagern des CSS-Codes in eine eigene Datei.

IntelliSense für JavaScript

IntelliSense kann endlich auch in <script type='text/javascript'>-Bereichen innerhalb einer Seite genutzt werden. Bisher funktioniert es nur in Dateien mit der Endung .js. Es arbeitet aber leider nicht in Eventhandlern wie onclick oder in <a href="javascript:-Bereichen.

Zusätzlich soll man auch in JavaScript debuggen können. Da reichte mir bisher auch der IE7-JS-Debugger und die Firebug-Extension für den Firefox. Im Rahmen der Nutzung der neuen AJAX-Bibliotheken ist ein integrierter Debugger von Vorzug.

Refactoring

Die angeboten und sehr nützlichen Refactoring-Methoden wurden leider nur minimal erweitert. Man kann die using-Anweisungen aufräumen: Unbenutze Einträge können nun automatisch entfernt werden. Für weitergehende Refactoring-Methoden ist man weiterhin auf Resharper oder ähnliche Add-Ins angewiesen.

Unit-Tests

Visual Studio 2008 Unit Tests

Ein eigener Menüpunkt in der Professional-Edition nennt sich Test. Der Aufruf erzeugt ein eigenes Projekt, dass automatisch der aktuellen Solution zugefügt wird. Man kann dabei alle Klassen oder Methoden markieren, für die man Test-Platzhalter erzeugen möchte. Auch nachträglich kann man bei jeder Funktion oder Klasse solche Platzhalter erzeugen lassen.

Das Testprojekt wird separat erzeugt und ausgeführt. Ergebnis ist eine Liste, in der man schnell die gescheiterten Tests sieht.

Ob NUnit dadurch überflüssig wird, muss sich aber noch zeigen.

Neue Bibliotheken

Zu den 70.000 Klassen und Methoden kommen einige tausend weitere hinzu. Die neuen Bibliotheken decken die Bereiche AJAX, SOA und die neue Vista-Präsentationsschicht WPF ab.

AJAX-Unterstützung

Die Microsoft-Tools zur nahtlosen Einbindung von asynchronen JavaScript-XML-Aufrufen sind kein Addon mehr, sondern integriert.

WCF

Die Windows-Communication-Foundation ist schon seit dem .NET-Framework 3.0 dabei und von daher nicht wirklich neu. Diese Bibliothek unterstützt die Erstellung von SOA Anwendungen, und geht über reine Webservices hinaus.

WPF-Designer

VS.NET08 WPF Designer

Auch schon in 3.0 enthalten war die Windows Presentation Foundation Biblitothek, nunmehr steht aber ein Designer hierfür bereit. Bisher musste man jedes WPF-Controls manuell im Code erzeugen. Das auch als Avalon bekannte API dient der Erzeugung von 2D- und 3D-Präsentations-Schichten.

Es ist auch für Webanwendungen interessant, um z.B. 3D-Grafiken dynamisch erzeugen zu können. WPF ermöglicht auf einfache Art und Weise, Grafik-Effekte einzusetzen, wie sie bisher nur unter Einsatz des sperrigen DirectX oder OpenGL erreichbar waren. Die Entsprechung im Web soll nach Microsofts Wollen Silverlight werden, das als Flash-Konkurrent konzipiert ist. Bis zur ersten akzeptablen 2.0-Version wird aber noch mindestens ein Jahr vergehen.

Neue Sprachkonstrukte in C# 3.0

In 2.0 kamen die mächtigen Generics hinzu, nun wird die Sprache C# konsequent weiterentwickelt. Es finden sich Anleihen bei Ruby und Phyton, ohne allerdings auf Typsicherheit zu verzichten.

Extension Methods

Extension Methods erlauben es, bestehende Objekte um weitere nützliche Methoden zu erweitern. Das funktioniert auch, wenn die zu erweiternde Klasse sealed ist, oder deren Quelltext nicht zur Verfügung steht.

Ein Beispiel sagt hier mehr als tausend Worte. Die beiden hier definierten Methoden IsEven und IsOdd erlauben es, für jede int-Zahl festzustellen, ob sie gerade oder ungerade ist.

public static class MyExtensions
{
	public static bool IsEven(this int vnNumber)
	{
		return vnNumber % 2 == 0;
	}
	public static bool IsOdd(this int vnNumber)
	{
		return !vnNumber.IsEven();
	}
}
...
if (5.IsOdd())
{
	...

Gegenüber einem
if (MyExtensions.IsOdd(5)) ...
ist es kürzer, und zudem stehen diese selbstdefinierten Extensions sofort per IntelliSense zur Verfügung. Extension Properties gibt es leider nicht.

Implizit typisierte lokale Variablen / Type Inference (var)

var lsText = new StringBuilder(); ist schneller zu tippen und zu lesen und zu ändern als die Dopplung: StringBuilder lsText = new StringBuilder();

Dadurch sind auch keine Code-Anpassungen mehr notwendig, wenn sich nur der Klassen-Name eines Rückgabeobjekts ändert.
var loMedia = loDoc.GetMedia(conn);
kann unverändert bleiben, auch wenn sich der Rückgabewert von GetMedia ändern sollte. Notwendige Änderungen meldet der Compiler, denn die Typsicherheit bleibt unverändert erhalten. Den richtigen Datentyp ermittelt der Compiler automatisch aus dem Teil auf der rechten Seite des Gleichheitszeichens.

Objekt- und Objektmengeninitialisierer

Die neue Objektinitialisierung ermöglicht lesbareren Code. Vorher hatte man oft bei der Instanzierung eine endlose Reihe von Parametern beim Aufruf des Konstruktors, deren Bedeutung sich nur durch Nutzung von IntelliSense erschloss. Nunmehr sieht man einfach die Bedeutung der einzelnen Werte. Natürlich lassen sich hierbei nur Properties ansprechen, die nicht readonly sind. Damit geht so etwas wie
var ldDatum = new DateTime() = {Year = 2007, Month = 12, Day = 4};
nicht, da diese Properties alle nur einen getter besitzen.

Lambda Expressions / Lambda Ausdrücke (=>)

Lambda expressions ersetzen de facto anonyme Methoden. Sie können alles, was anonyme Methoden bieten, sind aber einfacher und variabler im Einsatz.

Als Beispiel ein Vergleich zwischen einer anonymen Methode und einem lambda-Ausdruck.

Mittels Delegate:
foreach (var lnResult in lnaNumbers.Where(delegate(int p) { return p.IsOdd(); }))
{
	Out("odd number: " + lnResult);
}
Mittels Lambda-Expression:
foreach (var lnResult in lnaNumbers.Where(p => p.IsOdd()))
{
	Out("odd number: " + lnResult); 
}

Weitere Beispiele:

LINQ

LINQ dürfte die Ursache für die vielen Spracherweiterungen wie

  • Implizit typisierte Arrays
  • Anonyme Typen (Anonymous types)
  • Automatische Eigenschaften (Automatic Properties)
  • und auch die oben beschriebenen lambda-expressions
  • Object Initializer und Collection Initializer
  • Abfrageausdrücke (Query Expressions)

sein, denn LINQ wird erst durch diese Spracherweiterungen möglich. LINQ ist eine mächtige und gleichzeitig elegante Erweiterung. Es ermöglicht die Programmierung in einer SQL ähnlichen Notation, um auf XML-Daten oder SQL-Daten zuzugreifen, ohne dabei die Typsicherheit einzubüßen.

Enumerationen bleiben Sorgenkind

Mir persönlich fehlt ein aufgebohrter enum-Typus. Enumerationen sind weiterhin in keiner Weise erweiterbar, was deren Nutzen unnötig stark beschränkt. Java ist hier mittlerweile einen Schritt voraus .

Ich würde mir zusätzlich dazu noch hierarchische Enumerationen wünschen. Diese könnten die IntelliSense-Navigation in Konstantensammlungen vereinfachen:
Weltall.Milchstrasse.Sonnensystem.Erde.Europa.Deutschland.Nrw.Dortmund
anstelle von
Weltall.Milchstrasse_Sonnensystem_Erde_Europa_Deutschland_Nrw_Dortmund
Bisher dienen verschachtelte struct-Bereiche mit öffentlichen const-Membern als unbefriedigende Ersatzlösung.

Zusammenfassungen der Neuerungen

Viele weitere nützliche Online-Beiträge helfen, die Neuerungen und deren Nutzen zu erfassen. Schade, dass es kaum noch Zeitschriften gibt, die sich solch wichtigen Themen rasch und ausführlich genug widmen. Daher geht heutzutage kein Weg am Lesen von Blogs vorbei.

Downloads

Fazit

Die Neuerungen sind allesamt sehr nützlich und hilfreich. Man kann sofort vom Einsatz von Visual Studio 2008 profitieren, auch wenn man noch nicht die neuen Sprachfeatures nutzt, sondern weiterhin Anwendungen für das Framework 2.0 erstellt.

Man ist sehr verführt, alte Anwendungen sofort auf 3.5 umzustellen, um die zeitsparenden neuen Sprachkonstrukte nutzen zu können. Erste kleinere Projekte, wie auch diese Website, sind bereits umgestellt, und so wie es aussieht, werden in rascher Folge alle anderen folgen. Das einzige Argument gegen eine Umstellung ist, das solchermaßen umgestellte Anwendungen nicht mehr auf Windows 2000 laufen, sondern XP oder höher erfordern. Im Webanwendungsbereich ist das keine schwierige Entscheidung, denn hier muss kein Client sich umstellen.

Der Nutzen einer Umstellung hat die Kosten in Form von Zeitaufwand schnell wieder eingespielt. Die Umstellungskosten werden ja auch bei einer späteren Umstellung nicht geringer, allerdings hat man dann lange Zeit nicht von den Fortschritten profitiert.

Die Konsequenz:
Adios VS.NET 2005, willkommen VS08!