Datentypen in C#
Geschrieben von: Christian Holm In diesem Artikel möchte ich Ihnen die Datentypen von C# (sprich "C sharp") erklären. Obwohl C# mit C++ verwandt ist, hat sich auch einiges in der Definition und in der Behandlung der Datentypen geändert. So einfach sich dieses Thema vielleicht auch anhören mag, Datentypen stellen unter anderem die Grundstruktur eines Programmes dar, und können bei falscher Implementation zu ärgerlichen Compilerfehlern führen. Anmerkung: Dadurch daß in C#, wie auch in C++, der Sourcecode in Englisch gehalten ist, werde ich die sprachspezifischen Befehle, Schlüsselwörter etc., unverändert lassen und gegebenfalls das deutsche Äquivalent verwenden; z.B. floating point- / Fließkomma-. Einteilung der DatentypenGrundsätzlich lassen sich die Datentypen wie folgt in drei Kategorien einteilen:
Anmerkung zu "pointer-types": Diese Typen können nur im sogenannten Unsafe Code verwendet werden. Pointer (Zeiger) beinhalten Adressen zu Speicherorten. Da in dieser Hinsicht in C# Vereinfachungen für den Entwickler getroffen wurden (u. a. der Garbage Collector, kurz GC, der nun die Speicherverwaltung über hat) sollten diese nur mehr eingeschränkt verwendet werden, um Kollisionen mit geschütztem Speicherbereich oder "Exception Errors" zu vermeiden. Der Unterschied zwischen value-types und reference-types liegt darin, daß value-types die
tatsächlichen Daten
enthalten und reference-types einen Bezug auf die Daten beinhalten. Da jeder value-type eine eigene Kopie der Daten besitzt, können Manipulationen an der einen Variable die andere nicht beeinflußen.
Value-TypesDieser Datentyp ist entweder ein struct-Typ oder ein enumeration-Typ. C# enthält vordefinierte struct-types welche auch simple-types genannt werden. Eine Variable enthält immer einen Wert im Datentyp der ihr zugewiesen wurde. Bevor Sie in C# eine Variable verwenden können, müssen Sie diese zwingend vorher deklarieren. In C# werden die Variablen-Typen nun eingeteilt in:
Besprechen wir nun die simple-types: Diese unterteilen sich in
Die wichtigsten Datentypen seien hier ausführlicher beschrieben: Integral TypesIn C# gibt es neun integral-types: byte, sbyte, short, ushort, int, uint, long und ulong. Der Typ char soll später extra beschrieben werden. Die aufgezählten Datentypen haben folgende Eigenschaften:
Beachte: Wie Ihnen sicher schon aufgefallen ist, haben integer und long andere Gültigkeitsbereiche als in C++. In C# ist integer nicht mehr von einem word abhängig und long hat jetzt eine Bitgröße von 64 bit. Decimal TypeDer Decimal Datentyp hat eine Größe von 128 Bit. Er weist also eine hohe Genauigkeit gegenüber dem floating point-type auf, hat aber im Vergleich zum floating point-type einen engeren Gültigkeitsbereich. Dieser Datentyp ist dienlich für finanzmathematische Berechungen oder Währungsumrechungen. Der Gültigkeitsbereich geht von 1,0 * 10^-28 bis 7,9 * 10^28 mit 28-29 signifikanten Stellen. Beachte: Die Genauigkeit ist in signifikanten Stellen gegeben und nicht in Dezimalstellen. Rechenoperationen sind bis zu 28 Dezimalstellen genau. Auf Grund der besprochenen Unterschiede zwischen decimal und floating-point sollten sie auch vorsichtig beim umcasten (umwandeln) in die anderen Typen sein. Denn in die eine Richtung generieren sie möglicherweise einen Überlauf, in die andere verlieren Sie die Genauigkeit. Bei der Variablendeklaration ist folgendes zu beachten: Wenn Sie bei decimal Kommastellen benutzen wollen, so müssen Sie das mit einem m als Suffix angeben. Beispiel: decimal Wert = 3.4m; (Im C# Source Code gilt: Im Englischen gilt der Punkt als Komma!) Falls Sie den Suffix nicht angeben, wird die Variable vom Compiler als double behandelt floating point TypesEs gibt hierbei zwei unterschiedliche Typen float und double. Wie nicht anders zu erwarten unterscheiden sie sich im Gültigkeitsbereich und in der Genauigkeit.
bool TypeDieser verdient in C# Beachtung: im Gegensatz zu C++ sind boolsche Datentypen und Integer Datentypen nicht mehr ident! Das heißt, der boolsche Datentyp umfaßt nur mehr die Werte true oder false, und nicht mehr Null (0) oder einen von Null (0) ungleichen Wert. char TypeDieser Datentyp stellt ein Zeichen im Unicodeformat dar. Ein Unicodezeichen hat eine Größe von 16 bit und ist für die meisten Sprachen verwendbar. Um einer char-Variablen einen Wert zuzuweisen, geht man so vor, daß man den Buchstaben mit einfachen Anführungszeichen umgibt. In C# sieht dies dann so aus: char Variablenname = 'Unicode Zeichen'; // z.B char zeichen='C'; Zwei weitere Darstellungsmöglichkeiten für Unicode Zeichen sollen hier nur am Rande erwähnt werden - die Möglichkeit der
Beachte: Wenn Sie den char Datentyp umcasten wollen, müssen Sie das auch explizit tun (im Gegensatz zu C++), indem sie eine extra Anweisung schreiben. struct TypeEin struct Datentyp kann Konstanten, Felder, Methoden, Eigenschaften, Indexer, etc. deklarieren. Anders als in C++ werden in C# structs als Wert aufgefaßt und Klassen als Referenztyp. Der Grundgedanke bei der Verwendung von struct ist, daß man damit "Objekte" erstellt, die wesentlich weniger Speicherplatz als echte Objekte benötigen. Das kommt dadurch, daß keine zusätzliche Speicherreferenzen benötigt werden wie für Klassen. enumeration TypeWenn Sie einen spezielle Datentyp suchen, der eine Reihe von vordefinierten Konstanten enthalten kann, dann sollten Sie den Datentyp enumeration verwenden. Jeder enumeration-type hat seinen untergeordenten Datentyp (z.B. byte, short, integer oder long). Beispiel: enum Variablenname {Menge};
enum Woche {Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, Sonntag}; Sie können natürlich auch in der Mengenangabe einen anderen Datentyp angeben: Beispiel: enum Variablenname : Datentyp {Menge}; enum Woche : byte {Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, Sonntag}; Reference TypesEin reference-type kann eine Klasse, ein interface-type oder ein Array sein. Ein reference-type ist die Refernz zu einer Instanz, und damit letzlich zu einem Objekt. Der Wert null ist kompatibel mit allen Reference types und bedeutet die Nonexistenz einer Instanz. Der reference-type gliedert sich in folgende Untertypen:
Class typesDer Class type definiert eine Datenstruktur welche Daten-Member (Konstanten, Felder und Events) und Funktions-Member (Methoden, Eigenschaften, Indexer, Operatoren, Konstruktoren und Destruktoren) beeinhaltet. Class types unterstützen Vererbung; das bedeutet, daß hergeleitete Classes die Base Class erweitern und spezialisieren können. Delegate typesEin delegate ist ein Referenztyp der sich auf eine Methode oder auf eine Objektinstanz und die Instanzmethode dieses Objektes bezieht. Der nächste Verwandte zum delegate in C oder C++ ist der Funktionspointer (addressof in VB), wobei ein Funktionspointer nur statische Funktionen referenziert, der delegate jedoch statische und Instanzmethoden. Der delegate speichert nicht nur den Methodenanfangspunkt sondern auch eine Referenz zum Instanzobjekt um die Methode aufzurufen. Array typesEin Array ist eine Datenstruktur welche eine Anzahl von Variablen beeinhaltet die durch berechnete Indizes zugänglich ist. Die Variablen die sich in einem Array befinden, werden auch als Elemente eines Arrays bezeichnet und sind alle vom selben Typ. Dieser Typ wird als "Elementtyp des Arrays" bezeichnet. Mehr Informationen zu Arrays erhalten Sie in einem unserer nächsten Artikel. Object typeDer Object Type ist die ultimative Base class aller anderen Typen. Jeder Typ in C# läßt sich direkt oder indirekt vom Object Type herleiten. Das object Schlüsselwort ist einfach nur ein angenommener(anderer) Name für die vordefinierte System.Object Klasse. Das Keyword object ist genau das gleiche wie System.Object und umgekehrt. String typeDer String type ist ein abgeschlossener Class type welcher direkt von Object abgeleitet ist. Instanzen der String Class repräsentieren Unicode Zeichenfolgen. Das string keyword ist einfach nur ein anderer Name für die vordefinierte System.String Class. Der Keyword string ist genau das selbe wie System.String und umgekehrt. InterfacesEin Interface definiert einen Referenztyp der nur abstrakte Members (Mitglieder) hat. Ein interface wird dazu verwendet, um eine Schnittstellen-Vereinbarung zu schaffen. Eine Klasse oder ein struct, welches ein Interface implementiert, muß die Vereinbarung einhalten. Ein interface kann Methoden, Eigenschaften oder Indexer enthalten. Boxing und UnboxingBoxing und Unboxing ist ein zentraler Teil im Type-System von C# (und der Runtime). Es stellt ein Bindeglied zwischen value-types und reference-types zur Verfügung. Value-types haben den Vorteil, daß sie wenig Speicherplatz benötigen. In manchen Fällen ist es jedoch von Vorteil, daß value-types auch die die Eigenschaften von Objekten haben. Diese Übereinkunft macht den Hauptteil von C# aus, daß die Verknüpfung zwischen value-types und reference-types dadurch geschieht, daß ein value-type aus einem und in ein Objekt ungewandelt werden kann. Unter dem Motto "Es ist zwar alles ein Objekt, aber nur dann wenn es eines sein muß." Boxing VorgangDer Boxing Vorgang beschreibt die Umwandlung von einem value-type zu einem Objekt. Bei dem Boxing Vorgang wird die Instanz eines Objekts erstellt und der ursprüngliche Wert des value-types wird in das neue Objekt kopiert. Ein Beispiel: ... int nVariable = 1; object oVariable = nVariable; ... Hier geschieht folgendes: in der ersten Sourcecodezeile wird die Variable "nVariable" als integer Datentyp deklariert, und diese bekommt zusätzlich den Wert 1 zugewiesen. In der zweiten Zeile wird nun eine neue Instanz for das Objekt oVariable erstellt und ihr der Wert der Variable nVariable zugewiesen. Durch diesen Kopiervorgang erhalte ich 2 völlig unabhängige Variablen. Das heißt, wenn der Wert des Objekts oVariable geändert wird, dann hat sich der Wert von nVariable nicht ändert. Die folgende kleine Anweisung beweist dies: int nVariable = 1; object oVariable = nVariable; oVariable = 2; Console.WriteLine("{0} {1}", nVariable, oVariable); Die Werte, die ausgegeben werden sind einmal 1, und das zweite mal 2. Unboxing VorgangMan könnte sagen, dies sei der umgekehrte Vorgang. Beim Unboxing Vorgang wird ein value type aus einem Objekt extrahiert. Der C# Compiler überprüft zusätzlich, ob die von Ihnen angeforderte Variable, welche Sie aus dem Objekt extrahieren wollen, tatsächlich den angeforderten unboxed Type entsprechen kann. Ein Beispiel: ... int nVariable = 1; object oVariable = nVariable; int nUBVariable = (int)oVariable; ... Würde hier ein anderer Typ als int für die Unboxing Operation angefordert, bekäme man eine Exception. SchlußbemerkungDies ist zugegebenermaßen eines der trocken Kapitel aus der C#-Programmierung. In diesem Artikel habe ich versucht Ihnen die verschieden Datentypen vorzustellen und das umcasten von Variablen zu Objekten (boxing) und umgekehrt (unboxing). Obwohl C# einige, für den Programmierer vereinfachende Funktionen und Dienstleistungen zur Verfügung stellt, ist der richtige Umgang mit Datentypen von grundlegender Bedeutung. Verwandte Artikel
A Brief History of C# Wenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Eine weitere sehr hilfreiche Resource ist das deutsche ASP.NET Wiki, das als zentrale Anlaufstelle für Tips, Tricks, Know How und alles Nützliche was man in seinem Alltag als (ASP).NET-Entwickler so braucht und entdeckt gedacht ist. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |