ein Projekt von goloroden.de

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