C#

Programmieren mit C#


Programmieren mit C#

Für .NET hat Microsoft eine neue Programmiersprache entwickelt: C# (ausgesprochen »Ssi-sharp«). »Im Englischen bezeichnet der Name den Ton Cis und soll andeuten, dass sie einen Halbton höher steht als C++.« 1 Die herausragenden Merkmale von C# sind:

Durch die konsequente Typisierung und Objektorientierung wurden viele Probleme beseitigt, die z. B. in C++ enthalten sind. Vor allem wurden auch Fehlerquellen beseitigt, die für den Programmierer nur schwer zu finden sind, weil sie »nur« zu logischen Fehlern führen, mit denen sich der Code dennoch kompilieren lässt und ggf. auch lauffähig ist.

Zur Verwirklichung der Konzeption komponentenorientierter Software wurden Lösungen entwickelt, die es in bisherigen Programmiersprachen so noch nicht gibt. C# ermöglicht es, deklarativen Informationen - Attribute/Meta-Daten - jeder Komponente hinzuzufügen. C# Objekte werden ohne Header- und IDL-Dateien erstellt. Sämtliche Komponenten sind selbstbeschreibend und können ohne Registrierung eingesetzt werde, d. h., dass die Programmdateien einfach in ein Verzeichnis auf den ausführenden PC kopiert werden können. Kommentierungen im Quelltext ermöglichen das Generieren selbstbeschreibender Dokumentationen, die auch in XML exportiert werden können.

Die Informationen, die die Runtime für die Verwaltung des Codes benötigt, erhält sie in Form von Meta-Daten, die von den Assemblies zur Verfügung gestellt werden. .NET-Assemblies kann man als die entscheidende Baugruppe für Programmkomponenten betrachten. Solche Baugruppen können vollständig in einer einzelnen DLL enthalten sein oder sich auch aus vielen DLLs und Ressourcen zusammensetzen, die über mehrere Dateien verteilt sind.

Hyperlinks in HTML-Dokumenten werden gelegentlich als der Klebstoff bezeichnet, der das Web zusammenhält. Meta-Daten kann man als den Klebstoff von .NET Anwendungen betrachten. Sie stellen eine sehr umfangreiche Beschreibung der Bestandteile dar, die es in einer Baugruppe gibt. Sie enthalten Details wie zum Beispiel Beschreibungen der Klassen, Funktionen, Properties und Ressourcen sowie Informationen über die externen Baugruppen, die von einer Baugruppe benutzt werden und Versionsinformationen.

Interessant ist der Umgang mit Wertetypen. Während ein Teil bisheriger, objektorientierter Programmiersprachen entweder Abstriche an Paradigmen objektorientierter Programmierung (OOP) macht und einfache Typen nicht als Objekt, sondern eben gesondert behandelt, andere Sprachen dagegen auch einfache Typen immer als Objekt behandeln und dafür Leistungseinbußen hinnehmen, haben die Architekten des .Net Framework - auf das C# aufsetzt - für die Behandlung einfacher Typen eine sehr elegante Lösung geschaffen. Einfache Typen werden zunächst als einfache Typen erstellt und verwaltet, bei Bedarf (z. B. für einen Methodenaufruf) jedoch in ein Objekt um- und - sofern die Objekteigenschaft nicht mehr benötigt wird - wieder zurückgewandelt. Dies wird mit der Boxing-/Unboxing-Technik erreicht, die für den Programmierer transparent von Statten geht. Er kann somit einfache Typen genauso wie Objekte verwenden. Verwaltet werden sie jedoch nur dann als Objekt, wenn es notwendig ist. Im Ergebnis können Wertetypen immer wie Objekte behandelt werden, ein entscheidender Punkt, der C# zur einer wirklich objektorientierten Programmiersprache macht: »Alles ist ein Objekt«.

Enums (Aufzählungen) sind ein sinnvolles Konzept. Anders als z. B. in Java stehen Enums in C# zur Verfügung, selbstverständlich typsicher. In C# sind Enums nicht einfach nur Integer, wie in C++. Sie sind wirklich sichere Wertetypen und von System.Enum in der .NET Basisklassen Bibliothek abgeleitet. Ein Enum vom Typ »foo« ist ohne Cast nicht mit einem Enum vom Typ »bar« auswechselbar.

Die Sprachdesigner haben die Programmiersprache sehr eng an C++ angelehnt. Viele Schlüsselwörter, Operatoren sind in C# die gleichen wie in C++. Die Namensräume sind sehr ähnlich. Die Sprache wurde gegenüber C++ jedoch sehr stark vereinfacht. C# besitzt einerseits die Einfachheit und Klarheit von Visual Basic andererseits die Möglichkeiten von C++. Scheinbar unmöglich, aber wahr.

C# ist eine Programmiersprache für Microsoft .NET. C# Programme werden auf der Basis des .NET Framework - der .NET Common Language Runtime - erstellt und benötigen dieses zur Ausführung. Grundsätzlich ist es jedoch möglich in jeder Programmiersprache Anwendungen für das .NET Framework zu erstellen. Voraussetzung ist ein Compiler, der den Quellcode nicht wie bisher üblich in Maschinencode übersetzt, sondern in eine Zwischensprache (Microsoft Intermediate Language = MSIL, oder auch noch kürzer: IL). Den Code der Zwischensprache übersetzt ein JIT-Compiler (JIT = Just In Time) erst zur Laufzeit in Bytecode. Für C#, C++, J# und VB wird der Sprachcompiler schon mit der .NET-Plattform geliefert. Für andere Sprachen wurden Compiler - von anderen Herstellern - entwickelt.

Die Erzeugung von ausführbarem Byte-Code erfolgt in zwei Schritten:

  1. Kompilierung des Quellcodes in die Zwischensprache MSIL
  2. Kompilierung der Zwischensprache in nativen Code und Ausführung.

Dieses Konzept macht es möglich, betriebssystemunabhängige Programme zu erstellen.

Den ersten Schritt macht nur der Programmierer, wenn er sein Programm fertig gestellt hat, bevor er es in Form von DLL- bzw. EXE-Dateien Anwendern übergibt. EXE- und DLL-Dateien von .NET-Anwendungen enthalten keinen nativen Code mehr, sondern MSIL. Bei diesem Schritt erfolgt die Sprachintegration. MSIL sieht immer gleich aus, egal von welcher Sprache und für welches Betriebssystem.

Den zweiten Schritt übernimmt der Just In Time Compiler (JITer). Der JITer muss zwangsläufig in den Componenten des .NET-Framework auf ausführenden PCs enthalten sein. Er kann aber nur mit MSIL etwas anfangen, nichts mit C#-Code oder mit Quellcode anderer .NET-Sprachen. Der JITer gewährleistet die Betriebssystemunabhängigkeit von .NET-Anwendungen. Nicht die Anwendungsdatei (MSIL) kommuniziert mit dem Betriebssystem, sondern die Runtime des .NET Framework, die den Bytecode vom JITer erhält, der sich in der jeweiligen Betriebssystemausführung mit »seinem« Betriebssystem auskennt und aus MSIL den nativen Code (passenden Maschinencode) erzeugen kann. Der Bytecode wird also von der Runtime des .NET Framework »verwaltet« (verwalteter Code).

Die Funktionsweise der .NET Common Language Runtime (CLR) bei der Ausführung von verwaltetem Code ist keinesfalls mit der Arbeitsweise eines Interpreters zu verwechseln. Ein Interpreter interpretiert Code Stück für Stück und führt entsprechende Makrobefehle seiner Laufzeitumgebung aus. Das ist bei der CLR nicht der Fall. Der JIT-Compiler setzt die Beschreibung des Laufzeitverhaltens in ausführbaren Code um. Dies geschieht in der Regel nur einmal - vor der ersten Ausführung - und mit den Programmteilen, die gerade benötigt werden, wodurch übrigens unter Umständen verwalteter Code in der Ausführung sogar schneller als unverwalteter Code sein kann. Bei Bedarf wird aber auch der gesamte Code im Stück durch den JITer in Maschinencode compiliert (preJITing). Eine schrittweise Interpretation des Code findet nie statt.

1 c't 4/2001, S. 58


Valid XHTML 1.0! Valid CSS1! Level Triple-A conformance icon, W3C-WAI Web Content Accessibility Guidelines 1.0