Namensräume
Was sind Namensräume?
Die Typen, die während der Entwicklung einer Anwendung entstehen, werden jeweils mit
einem beschreibenden Namen versehen, welche Art von Daten dieser Typ verarbeiten soll.
Allerdings kann es durch den Einsatz von Komponenten vorkommen, dass zwei verschiedene
Typen unabhängig voneinander den gleichen Namen tragen, wobei der Name innerhalb der
jeweiligen Komponente eindeutig ist.
Um diese Typen dennoch unterscheiden zu können, werden sie üblicherweise in sogenannten
Namensräumen organisiert. Ein Namensraum stellt dabei einen Container dar, der die in
ihm enthaltenen Typen von den Typen anderer Namensräume abschottet. Wird ein Typ in
keinen Namensraum eingeordnet, befindet er sich automatisch im globalen Namensraum,
der mit global:: bezeichnet wird.
Innerhalb eines Namensraumes reicht der Name eines Typs zu seiner Identifikation aus.
Typen, die sich in anderen Namensräumen befinden, müssen jedoch zusätzlich mit ihrem
zugehörigen Namensraum angesprochen werden. Namensräume können zudem hierarchisch
angeordnet werden, um verschiedene Ebenen zu definieren. Der Name eines Typs
einschließlich seines kompletten Namensraumbezeichners wird als vollqualifizierter
Name bezeichnet.
Die Verschachtelung von Namensräumen wird in C# mit Hilfe des Punkt-Operators
durchgeführt, wobei der Punkt dann die einzelnen hierarchischen Ebenen voneinander
trennt.
Die FCL enthält bereits zahlreiche Namensräume, von denen der wichtigste System
heißt. In ihm befinden sich alle elementaren Typen, die zur Entwicklung von Anwendungen
benötigt werden. Unterhalb von System gibt es spezialisierte Namensräume wie
beispielsweise System.Data oder System.Xml zum Zugriff auf Datenbanken und
XML-Dokumente.
Generell gilt die Regel, dass der oberste Namensraum einer Komponente dem Namen der
Firma entsprechen sollte, welche die Komponente entwickelt. Darunter wird üblicherweise
ein Namensraum angeordnet, dessen Name dem der Komponente oder der Anwendung entspricht.
Weitere Namensräume, mit denen die verwendeten Typen detaillierter organisiert werden
können, finden sich schließlich auf der untersten Ebene.
Beispiele für Namensräume, die diesem Schema folgen, sind beispielsweise Microsoft.IE,
Microsoft.SqlServer.Server oder Microsoft.WindowsMobile.DirectX.Direct3D. Wichtig bei
der Benennung von Namensräumen ist, dass sprechende Namen verwendet werden, aus denen
hervorgeht, welche Arten von Daten die enthaltenen Typen abdecken. Außerdem muss das
erste Zeichen eines Namens ein Buchstabe oder ein Unterstrich sein, Ziffern oder sonstige
Zeichen sind nicht erlaubt.
Bei der Namensvergabe muss zudem beachtet werden, dass die Groß- und Kleinschreibung in
C# generell relevant ist. Daher bezeichnen die Namen System und system verschiedene
Namensräume. Für die Schreibweise zusammengesetzter Wörter wird in C# je nach Kontext
entweder Pascal Case oder Camel Case verwendet. In Pascal Case wird der Anfangsbuchstabe
jedes Wortes groß geschrieben, in Camel Case bildet das erste Wort hierzu eine Ausnahme,
da dessen Anfangsbuchstabe klein geschrieben wird.
Bei Namensräumen wird immer Pascal Case als Schreibweise verwendet, weswegen es
beispielsweise System.SqlServer und nicht system.sqlServer heißt.
Außerdem gelten in .NET für sämtliche Namen die Richtlinien, dass Abkürzungen nicht
und Akronyme nur dann verwendet werden, wenn sie allgemein gebräuchlich sind. Akronyme,
die aus höchstens zwei Zeichen bestehen, werden vollständig groß geschrieben, ab einer
Länge von drei Zeichen gilt wieder, dass je nach Kontext Pascal Case oder Camel Case
verwendet wird.
Auf Grund dieser Richtlinien heißt es System.IO an Stelle von System.Io und System.Xml
an Stelle von System.XML.
Schließlich ist noch zu beachten, dass Bezeichner nicht identisch mit Schlüsselwörtern
der Sprache C# sein dürfen - als Schlüsselwörter werden dabei alle Wörter bezeichnet,
die in C# bereits als Anweisung oder als sonstiger Ausdruck enthalten sind. Sofern der
Name eines Bezeichners zwingend einem Schlüsselwort entsprechen muss, wird dem Bezeichner
ein @ vorangestellt, wodurch der Bezeichner und das Schlüsselwort dann unterschieden werden
können. Diese Möglichkeit sollte allerdings nur in Ausnahmefällen in Betracht gezogen und
in der Regel vermieden werden.
Vordefinierte Namensräume
Verwendet man Typen aus einem anderen Namensraum in einer eigenen Komponente, so muss
jedes Mal der vollqualifizierte Name des Typs angegeben werden. Da die Lesbarkeit des
Codes bei tief verschachtelten Namensräumen dadurch beeinträchtigt werden kann, ist es
möglich, Namensräume einzubinden, so dass deren Typen so verwendet werden können, als
befänden sie sich im aktuellen Namensraum.
Dazu dient in C# die
using-Direktive, die in der Regel zu Beginn einer Datei angegeben
wird, wobei sich ein Namensraum durchaus über mehr als eine Datei erstrecken kann. Da
einige Namensräume wie unter anderem System von fast jeder Komponente benötigt werden,
fügen die meisten Entwicklungsumgebungen in eine neue Datei automatisch die
entsprechenden Zeilen ein.
| C# |
1
2
3
|
using System;
using System.Collections.Generic;
using System.Text;
|
Die Semikola am jeweiligen Zeilenende kennzeichnen in C# das Ende einer Anweisung. Da
jede Anweisung durch ein Semikolon abgeschlossen werden muss, kann sie auch auf mehrere
Zeilen verteilt werden, was bei langen Zeilen eventuell die Lesbarkeit verbessern kann.
Zudem werden zusätzliche Leerstellen und Leerzeilen ignoriert.
Die Namensräume alphabetisch zu sortieren und zwischen Namensräumen, deren oberste Ebene
sich unterscheidet, eine Leerzeile einzufügen, erleichtert das Auffinden eines bestimmten
eingebundenen Namensraumes und wird im allgemeinen als guter Stil angesehen.
| C# |
1
2
3
4
5
6
|
using Microsoft.IE;
using Microsoft.SqlServer.Server;
using System;
using System.Collections.Generic;
using System.Text;
|
Statt einen Namensraum einzubinden, kann alternativ ein Alias definiert werden, so dass
der Namensraum zumindest über einen kürzeren Namen angesprochen werden kann.
| C# |
1
2
|
using D3D =
Microsoft.WindowsMobile.DirectX.Direct3D;
|
Alle Typen, die im Namensraum Microsoft.WindowsMobile.DirectX.Direct3D enthalten sind,
können nun vollqualifiziert über den Alias D3D angesprochen werden. Ebenso kann ein
Alias für einen Typen definiert werden, indem statt eines Namensraumes der Name eines
Typs angegeben wird. Generell kann die Verwendung von Aliasen manchmal nützlich sein,
allerdings wird dieses Konstrukt in der Praxis eher selten genutzt.
Benutzerdefinierte Namensräume
Außer der Einbindung von bestehenden Namensräumen können auch eigene Namensräume
definiert werden, um eigene Typen zusammenzufassen und zu organisieren. Dazu dient in
C# die
namespace-Anweisung. Als Parameter erfordert sie den Namen eines Namensraumes,
zudem folgt ihr ein Namensraumrumpf, der von geschweiften Klammern eingeschlossen wird.
Anweisungen, denen ein durch geschweifte Klammern eingeschlossener Block folgt, werden
in C# nicht durch ein Semikolon abgeschlossen und stellen daher eine Ausnahme von der
Regel dar.
| C# |
1
2
3
4
5
|
using System;
namespace GoloRoden
{
}
|
Um verschachtelte Namensräume zu erstellen, kann eine weitere
namespace-Anweisung
in den Rumpf eingebettet werden. Die im Rumpf eingebetteten Zeilen einzurücken, erhöht
die Lesbarkeit, da Blockanfang und -ende sofort ersichtlich sind, zudem gilt dies
ebenfalls als guter Stil.
| C# |
1
2
3
4
5
6
7
8
|
using System;
namespace GoloRoden
{
namespace GuideToCSharp
{
}
}
|
Statt dessen kann auch direkt in der äußeren Anweisung der vollqualifizierte Name
des inneren Namensraumes angegeben werden.
| C# |
1
2
3
4
5
|
using System;
namespace GoloRoden.GuideToCSharp
{
}
|
Dieser Code kann nun mit Hilfe des C#-Compilers in MSIL übersetzt werden. Dabei besteht
prinzipiell die Möglichkeit, eine Komponente zur Verwendung in einer Anwendung mit der
Dateiendung .dll oder eine eigenständige Anwendung mit der Dateiendung .exe zu erzeugen.
Für eine eigenständig lauffähige Anwendung müssen allerdings einige Bedingungen erfüllt
werden, denen der vorliegende Code nicht gerecht wird, weshalb derzeit nur die Möglichkeit
besteht, eine Komponente zu erzeugen.
In .NET erfolgt das Kompilieren mit Hilfe des Compilers csc.exe, in Mono trägt der
Compiler den Namen mcs.exe.
Um in .NET eine Komponente zu erzeugen, muss der Compiler mit dem /target-Parameter
und dem Wert library aufgerufen werden, wobei /target optional als /t abgekürzt werden
kann. Zudem muss als weiterer Parameter die zu kompilierende Datei angegeben werden.
csc /target:library Component.cs
Die Parameter des Compilers von Mono sind kompatibel, so dass der Aufruf fast identisch
mit dem des Compilers von .NET ist.
mcs /target:library Component.cs
Das Ergebnis ist in beiden Fällen eine Assembly mit der Dateiendung .dll, die als
Komponente in einer Anwendung eingesetzt werden kann. Sofern ein anderer Name für
die Assembly vergeben werden soll, kann dazu so wohl in .NET wie auch in Mono der
Parameter /out verwendet werden.
csc /target:library /out:File.dll Component.cs
beziehungsweise
mcs /target:library /out:File.dll Component.cs