Ankündigung

Einklappen
Keine Ankündigung bisher.

C# FAQ für C++ Programmierer

Einklappen
Das ist ein wichtiges Thema.
X
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • C# FAQ für C++ Programmierer

    Die C# FAQ für C++ Programmierer wurde erstmals im August 2000 veröffentlicht und hat seitdem regelmäßig ein Update erfahren. Sie beantwortet viele Fragen die C++ Programmierer haben wenn sie das erste Mal auf C# treffen. Ich rate Ihnen dazu zunächst einmal die offizielle .NET Framework FAQ zu lesen bevor sie sich mit dieser hier vertraut machen.

    Die originale englische Fassung dieser FAQ stammt von Andy McMullan. Christopher Lauer hat diese auch in Französisch übersetzt. Gigix und Royal bieten zudem eine chinesische Version an. Die hier vorliegende deutsche Version wurde von Christian übersetzt und teilweise erweitert bzw. ergänzt .


    Aktuelle Updates:

    Inhalt






    1.1 Was ist C#?

    C# ist eine Programmiersprache welche von Microsoft entwickelt wurde. Sie ist an C/C++ angelehnt und hat wesentliche Gemeinsamkeiten mit Java. Sowohl C# als auch Java sind indirekte Abkömmlinge der C basierten Sprachfamilie und wurden eingeführt um ein neues Konzept in der Softwareprogrammierung einzuleiten. Nämlich den von verwalteten Code, auch Managed Code genannt. Microsoft beschreibt C# wie folgt:

    "C# ist eine einfache, moderne, objekt-orientierte und typsichere Programmiersprache. Sie beruht auf C und C++. C# (ausgesprochen 'C Sharp') ist fest in den Stammbaum der C und C++ Familie eingebettet und wird C und C++ Programmierern schnell vertraut sein. C# zielt darauf ab die hohe Produktivität von Visual Basic mit der rohen Leistungsstärke von C++ zu kombinieren."

    Sie können die ECMA C# Spezifikationen im PDF Format hier runterladen oder Jon Jagger's HTML-Version verwenden.


    1.2 Wie entwickle ich C# Applikationen?

    Die (kostenlose) .NET SDK enthält den C# Kommandozeilen Compiler (csc.exe). Die Visual Studio .NET Versionen haben eine vollständig intergrierte Unterstützung für die Entwicklung mit C#. Unter Linux können Sie auf das Projekt Mono zurückgreifen.


    1.3 Wird C# demnächst C++ ersetzen?

    Nein, definitiv nicht! C# wurde von Microsoft als Erweiterung der C Sprachfamilie eingeführt. Genausowenig wie C++ seinen kleinen Bruder C ersetzt hat, so wird auch C# C++ nicht ersetzen. C# steht als Programmiersprache für ein neues Konzept in der Computerprogrammierung. Das bedeutet das es weniger um eine Konkurrenz zwischen den Sprachen C# und C++ geht als vielmehr um die Unterschiede zwischen einem von einer Plattform verwalteten Code und dem bisherigen bekannten nativen Maschinencode.

    C# wurde speziell für das .NET Framework konzipiert und wird deshalb immer vollständig in Managed Code, die so genannte Microsoft Intermediate Language (MSIL), kompiliert. Als C++ Programmierer bleiben Ihnen die folgenden Möglichkeiten:
    • Benutzen Sie nur Standard C++. Greifen Sie nicht auf .NET zurück.
    • Benutzen Sie C++ mit .NET. Microsoft unterstützt für .NET zahlreiche Sprachen, darunter auch einen C++ .NET Compiler welcher im Grunde MSIL Code produziert. Wie auch immer, um in den vollen Genuß der .NET Umgebung zu gelangen (z.B. Garbage Collection) sind eine Reihe an zusätzlichen Erweiterungen zum C++ Standard von Nöten.
      In .NET 1.x werden diese Sprach-Erweiterungen "Managed Extensions" für C++ genannt. In .NET 2.x wurden die Managed Extensions unter der Führung von Stan Lippman und mithilfe von Bjarne Stroustroup komplett überarbeitet. ME C++ wurde von Microsoft in C++/CLI umbenannt.
    • Benutzen Sie ausschließlich C#! Binden Sie ggf. notwendigen C++ Code über Dynamic Link Libraries ein.
    Jede dieser Optionen hat Vor- und Nachteile, abhängig vom Entwickler und den Anwendungen die er/sie schreibt. Ich für meinen Teil versuche C# überall dort einzusetzen wo es möglich ist. Grund hierfür ist die unschöne Vereinbarkeit von C++ Code mit .NET. ME C++ (bald C++/CLI) ist allerdings sehr nützlich für die Interaktion zwischen dem neuen .NET Code und nativen C++ Code. Gegebenenfalls können Sie einfach eine Managed Wrapper Klasse in C++/CLI schreiben und diese dann in Ihrem C# Code benutzen. Aus eigener Erfahrung weiß ich, dass das sehr gut klappt.

    Der Erfolg von managed C++ wird allerdings maßgeblich vom Erfolg der Common Language Infrastructure abhängen. Sollte sich das C++/CLI-Design durchsetzen können, wäre C++ auch in Zukunft auf dem Gebiet der clientseitigen Windows-Applikationen uneingeschränkt konkurrenzfähig. Aufgrund des jungen Alters der CLI lässt sich aber zum gegenwärtigen Zeitpunkt keine genaue Prognose dazu abgeben, weshalb Sie die Entwicklung von C++ genau im Auge behalten sollten. Einen Umstieg auf C# könnten Sie sich jedoch auf diese Art und Weise ersparen. Einige Informationen zu C++/CLI und auch C++0x selbst können Sie in der Präsentation "C++: Future Directions in Language Innovation" finden, welche vom führenden Microsoft Software Architekten und Mitglied des C++ Standard Komittees Herb Sutter stammt.


    1.4 Besitzt C# seine eigene Klassenbibliothek?

    Nicht direkt. Das .NET Framework hat eine umfassende Klassenbibliothek auf welche C# und eben auch z.B. C++/CLI zugreifen kann. C# selbst hat keine eigene Klassenbibliothek.




    2.1 Welche Standard Typen benutzt C#?

    C# unterstützt eine sehr ähnliche Anzahl an Basis-Typen wie C++. Diese sind int, long, float, double, char, string, arrays, structs und Klassen. Erwarten Sie aber nicht zuviel. Die Namen ähneln sich zwar stark, dennoch unterscheiden sie sich im Detail. Beispielsweise ist ein long in C# immer 64Bit, während in C++ dies von der verwendeten Plattform (üblicherweise 32Bit auf 32Bit-Prozessorsystemen und 64Bit auf 64Bit-Prozessorsystemen) abhängig ist. Zudem sind in C++ Strukturen und Klassen fast dasselbe. In C# ist das nicht der Fall. Zuletzt werden chars und strings in .NET als 16-bit Datentypen (Unicode/UTF8) kompiliert während in C++ diese in der Regel 8-bit Datentypen sind.


    2.2 Ist es wahr das alle C# Typen von einer gemeinsamen Basis Klasse abgeleitet sind?

    Ja und Nein. Alle Typen können so behandelt werden als wären sie von Object (System.Object) abgeleitet. Aber um eine Instanz eines Werttyp's (z.B. int, float) als Object Ableitung behandeln zu können, muss die Instanz in einen Verweistyp konvertiert werden indem ein Prozess namens 'boxing' aufgerufen wird. In der Theorie kann ein Entwickler das alles unbeachtet lassen und die Laufzeitumgebung sich um die Konvertierungen kümmern lassen sofern diese notwendig sind. In der Realität kann diese implizite Umwandlung Nebenwirkungen haben welche sich als Stolperstein herausstellen können.


    2.3 Also kann ich eine Instanz eines Werttypen in eine Methode welche ein Objekt als Parameter verlangt übergeben?

    Ja, zum Beispiel so:

    Code:
    class CApplication
    {
        public static void Main()
        { 
            int x = 25; 
            string s = "fred"; 
            
            DisplayMe( x ); 
            DisplayMe( s ); 
        } 
        
        static void DisplayMe( object o ) 
        { 
            System.Console.WriteLine( "You are {0}", o ); 
        }
    }
    Dies erzeugt folgende Ausgabe:

    You are 25
    You are fred
    2.4 Was sind die fundamentalen Unterschiede zwischen Werttypen und Verweistypen?

    C# unterteilt Typen in zwei Kategorien - Werttypen und Verweistypen. Die meisten der intrinsischen Typen (z.B. int, char) sind Werttypen. Strukturen sind auch Werttypen. In den Bereich der Verweistypen fallen Klassen, Array's und Strings. Die zugrundeliegende Idee dahinter ist klar. Eine Instanz eines Werttyp's repräsentiert die tatsächlichen Daten, während ein Verweistyp einen Zeiger oder einen Verweis, auch eine Referenz genannt, auf die Daten darstellt.

    Das verwirrende an dem Aspekt für C++ Programmierer ist das C# festlegt welche Typen als Wert repräsentiert werden und welche als Referenz. Ein C++ Programmierer erwartet dass er das selbst bestimmen kann.

    In C++ können wir zum Beispiel das hier machen:

    Code:
    int x1 = 3;        // x1 ist ein Wert auf dem Stack
    int *x2 = new int(3)    // x2 ist ein Zeiger auf einen Wert auf dem Heap
    Während in C# man dies nicht selbst bestimmen kann.

    Code:
    int x1 = 3;        // x1 ist ein Wert auf dem Stack
    int x2 = new int(); 
    x2 = 3;        // x2 ist auch ein Wert auf dem Stack!

    2.5 Okay, also ist ein int ein Werttyp, und eine Klasse ist ein Verweistyp. Wie kann int von Object abgeleitet sein?

    Das ist es nicht wirklich. Wenn ein int auch als int verwendet wird ist es ein Wert. Wenn as dagegen als Objekt verwendet wird ist es eine Referenz auf einen Integer Wert (auf dem verwalteten Heap). Mit anderen Worten, wenn Sie einen int als Objekt benutzen, wandelt die Laufzeit diesen Integer Wert automatisch in einen Objektverweis um. Dieser Prozess wird boxing genannt. Die Konvertierung beinhaltet den Kopiervorgang des int in den Heap und die Erstellung einer Instanz welche darauf zeigt. Der Prozess des Unboxings ist der umgekehrte Fall.

    Code:
    // neuer int Wert 3 auf dem Stack
    int x = 3;   
    // neuer int auf dem Heap, auf 3 gesetzt, x existiert immer noch auf dem Stack
    object objx = x;
    // neuer Wert 3 auf dem Stack, x immer noch im Stack und objx auf dem Heap
    int y = (int)objx;

    2.6 Sind C# Referenzen dasselbe wie C++ Referenzen?

    Nicht ganz. Die Grundidee ist diesselbe, aber ein signifikanter Unterschied liegt darin das C# Referenzen null sein können. Deshalb können Sie sich nicht darauf verlassen das eine C# Referenz auf ein gültiges Objekt verweist. In diesem Sinne ist ein C# Verweis einem C++ Pointer ähnlicher als den bekannten C++ Referenzen. Wenn Sie versuchen einen Nullverweis zu benutzen wird eine NullReferenceException als Exception Objekt ausgeworfen.

    Schauen Sie sich mal folgende Mehode an:

    Code:
    void displayStringLength( string s )
    {
        Console.WriteLine( "String is length {0}", s.Length );
    }
    Das Problem an dem Code ist das eine NullReferenceException ausgeworfen wird wenn es wie folgt aufgerufen wird:

    Code:
    string s = null;
    displayStringLength( s );
    Natürlich kann es sein das Sie eine NullReferenceException nicht auslösen möchten. In diesem Fall können Sie auch eine Methode wie diese hier schreiben:

    Code:
    void displayStringLength( string s )
    {
        if( s == null )
            Console.WriteLine( "String is null" );
        else
            Console.WriteLine( "String is length {0}", s.Length );
    }



    3.1 Strukturen sind meistens überflüssig in C++. Warum hat C# Strukturen?

    In C++ ist eine Struktur und eine Klasse annähernd dasselbe. Der einzige Unterschied besteht darin, dass die Sichtbarkeit in einer Struktur standardmäßig als public definiert ist, während Elemente und Methoden in einer Klasse ohne explizite Angabe immer private sind. In C# sind Strukturen und Klassen sehr unterschiedlich. Während Strukturen in C# Werttypen sind, (Instanzen welche direkt auf dem Stack gespeichert werden oder Inline innerhalb der Heap-basierten Objekte) stellen Klassen Verweistypen (Instanzen die auf dem Heap gespeichert und indirekt über Referenzen adressiert werden) dar. Ebenso können Strukturen nicht von anderen Strukturen oder Klassen erben obwohl sie Schnittstellen implementieren können. Strukturen haben auch keine Destruktoren. Eine C# Struktur ähnelt eher einer C Struktur als einer C++ Stuktur.


    3.2 Unterstützt C# Mehrfachvererbung (MI)?

    Nein, obwohl es die Implemetierung von multipelen Schnittstellen in einer einzelnen Klasse oder Struktur unterstützt.


    3.3 Ist ein C# Interface dasselbe wie eine abstrakte C++ Klasse?

    Nein, eher nicht. Eine abstrakte Klasse in C++ kann nicht initialisiert werden. Es können also keine Objekte einer abstrakten Klasse welche nur über virtuelle Methoden verfügt erzeugt werden. Allerdings kann (und oft ist es so) eine abstrakte Klasse implementierten Code und/oder Datenelemente enthalten. Eine C# Schnittstelle (Interface) kann keinen implementierten Code oder Datenelemente enthalten - es ist einfach eine Gruppe von Methoden Namen & Signaturen. Die C# Schnittstelle ist wie eine COM Schnittstelle strukturiert und nicht wie eine abstrakte C++ Klasse.


    3.4 Sind C# Konstruktoren dasselbe wie C++ Konstruktoren?

    Sie sind in der Tat sehr ähnlich, aber es gibt einige signifikante Unterschiede. C# unterstützt die Verkettung von Konstruktoren. Das bedeutet das ein Konstruktor einen anderen aufrufen kann.

    Code:
    class Person
    {
        public Person( string name, int age ) { ... }
        public Person( string name ) : this( name, 0 ) {}
        public Person() : this( "", 0 ) {}
    }
    Ein anderer Unterschied besteht darin, dass virtuelle Methodenaufrufe innerhalb eines Konstruktors weitergeleitet werden zu der entsprechenden abgeleiteten Implementierung - siehe "Kann ich eine virtuelle Methode aus einem Konstruktor/Destruktor aufrufen?".

    Die Fehlerbehandlung ist ebenfalls ein wenig anders. Wenn eine Ausnahme während der Konstruierung eines C# Objektes erfolgt, wird der spezielle Destruktor, nämlich der Finalizer, dennoch aufgerufen. Dies unterscheidet sich zu C++, wo der Destruktor nicht aufgerufen wird wenn die Konstruierung nicht vollständig ist. (Vielen Dank an Jon Jagger für diesen Hinweis)

    Zuletzt hat C# statische Konstruktoren. Statische Konstruktoren sind nicht an Instanzen der Klasse gebunden, sondern sind feste Bestandteile der jeweiligen Klasse. Sie werden aufgerufen bevor die erste Instanz überhaupt erzeugt wird.

    Beachten Sie außerdem das wie in C++ einige C# Entwickler so genannte Factory Method Pattern gegenüber Konstruktoren bevorzugen. Sehen Sie dazu einen Artikel von Brad Wilson's.


    3.5 Sind C# Destruktoren dasselbe wie C++ Destruktoren?

    Nein. Sie sehen gleich aus, sind aber sehr unterschiedlich. Der C# Destruktor welcher mit dem auch aus C++ bekannten ~ Tilde Zeichen beginnt ist nur ein krönender Zusatz für eine Überbrückung der System.Object Finalize Methode. Diese Finalize Methode wird durch den Garbage Collector aufgerufen sobald dieser registriert dass auf das Objekt nicht mehr verwiesen wird. Anschließend gibt er den für dieses Objekt reservierten Speicherplatz frei. Bis hierhin klingt es wie ein C++ Destruktor. Der Unterschied liegt darin, dass der Garbage Collector keine Garantie darauf gibt wann dieser Schritt während der Programmausführung erfolgt. Tatsächlich kann es sein das der Algorithmus im Garbage Collector welcher über diesen Schritt bestimmt, den Speicher des Objektes erst viel später wieder freigibt. Diese Manko an Kontrolle und Gewissheit wird oft als 'nicht-deterministischer Abschluss' bezeichnet. Das bedeutet dass C# Destruktoren nicht dafür geeignet sind knappe Ressourcen, wie z.B. Datenbankverbindungen, Datei-Handler usw. freizugeben.

    Um eine sichere und deterministische Zerstörung zu erreichen muss eine Klasse eine Methode bereitstellen die dies ermöglicht. Die normale Vorgehensweise dabei ist eine IDisposable Schnittstelle zu implementieren. Der Benutzer des Objektes muss explizit die Dispose() Methode aufrufen wenn die Lebensdauer des Objektes endet, d.h. wenn das Objekt nicht mehr gebraucht wird. Um diesen Schritt zu vereinfachen stellt C# das 'using' Konstrukt zur Verfügung.


    3.6 Wenn C# Destruktoren so unterschiedlich zu C++ Destruktoren sind, warum verwendet MS diesselbe Syntax?

    Höchstwahrscheinlich wollten sie erreichen das sich C++ Programmierer mit der C# Syntax schnell wohl und vertraut fühlen. Ich denke aber das sie damit einen Fehler gemacht haben.


    3.7 Sind alle Methoden in C# virtuell?

    Nein. So wie in C++ sind Methoden nicht virtuell solange sie nicht explizit als virtuell ausgezeichnet werden.


    3.8 Wie deklariere ich eine reine virtuelle Funktion in C#?

    Benutzen Sie das Schlüsselwort abstract an der Methode. Die Klasse selbst muss ebenfalls mit dem Klassenmodifizierer abstract markiert werden. Darüberhinaus ist die Klasse automatisch abstrakt wenn eine oder mehrere Methoden einer Klasse abstrakt gemacht werden. Beachten Sie das abstrakte Methoden im Gegensatz zu reinen virtuellen C++ Methoden über keine Implementierungen verfügen können. Sie sind daran zu erkennen das sie keinen Rumpf besitzen und nur mit einem Semikolon enden!


    3.9 Kann ich eine virtuelle Methode aus einem Konstruktor/Destruktor aufrufen?

    Ja, aber das ist in der Regel keine gute Idee. Der Mechanismus der Objekt Konstruierung in .NET ist zu C++ sehr unterschiedlich und dies beeinflusst virtuelle Methodenaufrufe in Konstruktoren.

    C++ konstruiert Objekte von der Basis der abgeleiteten Klasse. Wenn der Basis-Konstruktor ausgeführt wird ist das Objekt tatsächlich ein Basisobjekt und virtuelle Mehodenaufrufe werden zur Basisklassen-Implementierung geleitet. Im Gegensatz dazu wird in .NET der abgeleitete Konstruktor zuerst ausgeführt was bedeutet dass das Objekt immer ein abgeleitetes Objekt ist und virtuelle Methodenaufrufe werden immer zu der abgeleiteten Implementierung geleitet. (Beachten Sie das der C# Compiler beim Start des abgeleiteten Konstruktors einen Aufruf in den Basisklassen-Konstruktor einfügt. Auf diese Art und Weise wird das Konzept der OO aufrecht erhalten indem die Illusion erzeugt wird das der Basis-Konstruktor als erstes ausgeführt wird.)

    Dasselbe trifft auch in dem Fall zu wenn virtuelle Methoden aus einem Konstruktor aufgerufen werden. Ein virtueller Methodenaufruf in einem Basis-Konstruktor wird zur abgeleiteten Implementierung geleitet.


    3.10 Sollte ich meinen Destruktor virtuell machen?

    Ein C# Destruktor ist wirklich nur eine Überbrückung der System.Object Finalize Methode und ist deshalb in der Definition virtuell.




    4.1 Kann ich Ausnahmen in C# verwenden?

    Ja. Tatsächlich sind Exceptions ein wesentlicher Grundstein in C# und in .NET allgemein. Die meisten Klassen des .NET Frameworks nutzen Ausnahmen um Fehler zu signalisieren.


    4.2 Welche Typen von Objekten kann ich als Ausnahme auswerfen?

    Nur Instanzen der System.Exception Klassen oder Klassen die von System.Exception abgeleitet sind. Das ist ein wesentlicher Unterschied zu C++ wo Instanzen von fast jedem Typ ausgeworfen werden können.


    4.3 Kann ich meine eigenen Ausnahmen definieren?

    Ja, leiten Sie dazu einfach Ihre Exception Klasse von System.Exception ab.

    Beachten Sie das Sie einige zusätzliche Arbeit machen müssen wenn Sie mit Ihrer Exception .NET Remote Grenzen überqueren möchten - siehe http://www.thinktecture.com/Resource...xceptions.html für weitere Details.


    4.4 Besitzt die System.Exception Klasse irgendwelche coolen Features?

    Ja - ein Feature welches besonders hervorsticht ist die StackTrace Eigenschaft. Diese liefert einen Stackaufruf welcher registriert wo die Exception genau ausgeworfen wurde. Zum Beispiel in diesem Code:

    Code:
    using System;
    
    class CApp 
    {  
        public static void Main() 
        { 
            try 
            { 
                f(); 
            } 
            catch( Exception e ) 
            { 
                Console.WriteLine( "System.Exception stack trace = \n{0}", e.StackTrace ); 
            }
        } 
    
        static void f() 
        { 
            throw new Exception( "f went pear-shaped" ); 
        } 
    }
    Der zugehörige Output:

    System.Exception stack trace =
    at CApp.f()
    at CApp.Main()
    Beachten Sie das dieser StackTrace von einem Debug Build produziert wurde. Ein Release Build optimiert vielleicht einige Methodenaufrufe weg, so dass der Stackaufruf eventuell anders ausfällt als Sie es erwarten.


    4.5 Wann sollte ich eine Ausnahme auswerfen?

    Über dieses Thema wird oft debattiert und es ist teilweise eine Frage des persönlichen Geschmacks. In der Regel ist es üblich das Exceptions dann ausgeworfen werden sollten wenn ein 'unerwarteter' Fehler auftritt. Wie entscheidet man ob ein Fehler erwartet oder unerwartet ist? Dies ist eine nicht so klar zu beantwortende Frage. Als geeignetes Beispiel lässt sich aber sagen, dass man das Scheitern eines Leseversuchs in einer Datei, infolge eines am Dateiende stehenden Seek Pointers als erwarteten Fehler ansehen kann, währenddessen der gescheiterte Versuch Speicher auf dem Heap zu allokieren als unerwarteter Fehler bezeichnet wird.


    4.6 Hat C# eine 'throws' Klausel?

    Nein, im Gegensatz zu Java braucht und erlaubt es C# dem Entwickler auch nicht Ausnahmen zu spezifizieren welche eine Methode auswerfen kann.




    5.1 Wie kann ich den Typ eines Objektes zur Laufzeit überprüfen?

    Sie können dieses Schlüsselwort benutzen. Zum Beispiel:

    Code:
    using System; 
    
    class CApp
    {
        public static void Main()
        { 
            string s = "fred"; 
            long i = 10; 
    
            Console.WriteLine( "{0} is {1}an integer", s, (IsInteger(s) ? "" : "not ") ); 
            Console.WriteLine( "{0} is {1}an integer", i, (IsInteger(i) ? "" : "not ") ); 
        }
        
        static bool IsInteger( object obj )
        { 
            if( obj is int || obj is long )
                return true; 
            else 
                return false;
        }
    }
    Mit der Ausgabe:

    fred is not an integer
    10 is an integer

    5.2 Kann ich den Namen des Typ's während der Laufzeit erhalten?

    Ja, benutzen Sie dazu die Get Type Methode der Object Klasse (von welcher sich alle Typen ableiten). Zum Beispiel:

    Code:
    using System; 
    
    class CTest
    {
        class CApp 
        {
            public static void Main()
            { 
                long i = 10; 
                CTest ctest = new CTest(); 
    
                DisplayTypeInfo( ctest ); 
                DisplayTypeInfo( i ); 
            }
            
            static void DisplayTypeInfo( object obj ) 
            { 
                Console.WriteLine( "Type name = {0}, full type name = {1}", obj.GetType(), obj.GetType().FullName ); 
            }
        }
    }
    Der Code erzeugt folgende Ausgabe:

    Type name = CTest, full type name = CTest
    Type name = Int64, full type name = System.Int64



    6.1 Wie kann ich einen String ohne Beachtung der Groß-/Kleinschreibung vergleichen?

    Benutzen Sie die String.Compare Funktion. Als überladene Funktion besitzt ihr dritter Parameter einen Boolschen Wert welcher die Groß-/Kleinschreibung beim Vergleich berücksichtigt oder nicht.

    Code:
    "fred" == "Fred"    // false
    System.String.Compare( "fred", "Fred", true )    // true
    6.2 Unterstützt C# eine variable Anzahl an Argumenten?

    Ja, indem das Schlüsselwort params verwendet wird. Die Argumente sind als eine Liste von Argumenten bestimmten Typ's spezifiziert, z.B. int. Für die ultimative Flexibilität kann der Typ object sein. Das Paradebeispiel einer Methode welche dies verwendet ist System.Console.WriteLine().


    6.3 Wie kann ich Kommandozeilen Argumente verarbeiten?

    Wie folgt:

    Code:
    using System;
    
    class CApp
    {
            public static void Main( string[] args )
            {
                    Console.WriteLine( "You passed the following arguments:" );
                    foreach( string arg in args )
                    Console.WriteLine( arg );
            }
    }

    6.4 Überprüft C# Array-Grenzen?

    Ja. Eine IndexOutOfRange Exception wird benutzt um einen Fehler zu signalisieren.


    6.5 Wie kann ich sicherstellen das meine C# Klassen mit anderen .NET Sprachen interoperieren können?

    Stellen Sie sicher das Ihr C# Code dem Common Language Subset (CLS) entspricht. Um dies zu erzwingen können Sie das globale Attribut [assembly:CLSCompliant(true)] Ihren C# Quelldateien hinzufügen. Der Compiler wird einen Fehler melden wenn Sie ein C# Feature verwenden welches nicht CLS verträglich ist.


    6.6 Wie benutze ich das Schlüsselwort 'using' mit multipelen Objekten?

    Sie können using Angaben wie folgt verschachteln:

    Code:
    using( obj1 )
    {
            using( obj2 )
            {
                    ...    
            }
    }
    Etwas schöner in der Syntax aber dennoch identisch zu dem obigen Code:

    Code:
    using( obj1 )
    using( obj2 )
    {
            ...
    }

    6.7 Was ist der Unterschied zwischen == und object.Equals?

    Bei Werttypen vergleichen == and Equals() normalerweise zwei Objekte an dem Wert. Zum Beispiel:

    Code:
    int x = 10;
    int y = 10;
    Console.WriteLine( x == y );
    Console.WriteLine( x.Equals(y) );
    Anzeige:

    True
    True
    Für Verweistypen ist die Sache ein wenig komplexer. Die Anwendung des Operators == führt bei Verweistypen zu einem Vergleich der Kennung. Das bedeutet das bei der Anwendung nur dann 'True', also Wahr, herauskommt wenn beide Referenzen auf dasselbe Objekt zeigen. Im Kontrast dazu führt die Funktion Equals() einen Vergleich des Wertes auf welchen die einzelnen Referenzen zeigen durch. Siehe:

    Code:
    StringBuilder s1 = new StringBuilder("fred");
    StringBuilder s2 = new StringBuilder("fred");
    Console.WriteLine( s1 == s2 );
    Console.WriteLine( s1.Equals(s2) );
    Gibt folgendes aus:

    False
    True
    s1 und s2 sind unterschiedliche Objekte, daher gibt == False zurück. Aber sie enthalten denselben Wert, nämlich den string "fred" und deshalb liefert Equals() True zurück.

    Leider haben Regeln oft auch Ausnahmen. Und deshalb vergleicht die Implementierung von Equals() in System.Object (diejenige welche Sie standardmäßig erben werden wenn Sie eine Klasse schreiben) die Kennung. Es ist dasselbe wie bei operator==. Deshalb führt Equals() nur dann einen Vergleich des Wertes durch wenn der Klassenautor die Methode überschreibt und sie korrekt implementiert. Eine weitere Ausnahme ist die string Klasse - ihr operator== vergleicht Werte eher als Kennungen.

    Zusatzbemerkung: Wenn Sie einen Vergleich der Kennung durchführen möchten benutzen Sie die ReferenceEquals() Methode. Sofern Sie einen Wertevergleich durchführen möchten verwenden Sie Equals() aber seien Sie sich bewußt dass das nur funktionieren wird wenn der Typ die Standard Implementierung überschrieben hat. Vermeiden Sie operator== an Verweistypen (außer vielleicht bei strings), da dieser einfach zu mehrdeutig ist.


    6.8 Wie erzwinge ich const Korrektheit in C#?

    Das können Sie nicht. Zumindest nicht auf diesselbe Art und Weise wie Sie es in C++ machen können. C# (genauer die CLI) hat kein echtes Konzept der const Korrektheit. Zum Beispiel gibt es keinen Weg eine Methode zu spezifizieren welche die an sie übergebenen Argumente nicht modifizieren soll/darf. Und es gibt auch keinen Weg eine Methode davon abzuhalten eines Ihrer Objekte zu modifizieren.

    Um ein Gefühl dafür zu bekommen welche Ängste dies bei C++ Programmierern hervorruft sollten Sie sich die Feedbacks auf Raymond Chen's Seite durchlesen. Dort finden Sie auch einen Verweis auf den Blog von CLI Lead-Designer Stan Lippman.

    Es gibt aber auch Ansätze dafür optionales Read-Only Verhalten bei Klassensammlungen zu erreichen. Sehen Sie sich dazu Brad Abram's Posting an.




    7.1 Was sind die neuen Features in C# 2.0?

    Unterstützung für alle neuen Framework Features, wie die Generics, anonyme Methoden, partiale Klassen, Iteratoren und statische Klassen. Sehen Sie sich die .NET FAQ für weitergehende Details an.

    Delegate Schnittstellen sind ein neues Feature des C# Compilers. Ein Delegate ist technisch gesehen ein Referenztyp, der dazu dient, eine Methode mit einer bestimmten Signatur und einem bestimmten Rückgabetyp zu kapseln. Das neue C# Feature vereinfacht ein wenig die Benutzung. Es erlaubt Ihnen folgendes zu schreiben:

    Code:
    Thread t = new Thread(ThreadFunc);
    Anstatt:

    Code:
    Thread t = new Thread( new ThreadStart(ThreadFunc) );
    Eine weitere kleine aber feine Erweiterung ist der explizite Namensraum. Dies schließt eine Lücke in C# 1.x. Sie können nun das Prefix global:: einem Typnamen voranstellen um zu kennzeichnen das dieser zu einem globalen Namesraum gehört. Auf diese Art vermeiden Sie dort Probleme wo der Compiler den Namensraum schließt und damit falsch liegt.

    Schlussendlich beinhaltet C# 2.0 einige syntaktische Schmankerl für den neuen System.Nullable Typ. Sie können T? als ein Synonym für System.Nullable verwenden, bei dem T ein Werttyp ist. Wie aus dem Namen vermutet werden kann erlaubt das Werten des Typ's 'null' oder 'undefiniert' zu sein.


    7.2 Sind C# Generics dasselbe wie C++ Templates?

    Nicht wirklich. Es gibt einige Ähnlichkeiten, aber es gibt andererseits auch fundamentale Unterschiede. Ein wichtiger Unterschied liegt darin, dass generische Typen in C# erst zur Laufzeit zu ihrem spezifischen Typ expandiert werden und der JIT-Compiler den Code verschiedener Instanzen gemeinsam verwenden kann. Dies soll die drastische Aufblähung des Code, wie bei C++ Templates mindern. Sehen Sie sich zu diesem Thema die .NET FAQ an.




    8.1 Bücher

    Ich empfehle Ihnen die folgenden Bücher. Zum Einen weil diese mir persönlich gut gefallen und zum Anderen weil diese unter den C# Entwicklern verbreitet sind. Die hier auf CodePlanet aufgeführten vom Original Autor empfohlenen englischen Bücher decken sich größtenteils mit den meinigen. Deshalb und weil ich sie selbst besitze habe ich diese als deutsche Version verlinkt. Einige weitere kann man ebenfalls als Referenzbücher zu C# ansehen.
    • Microsoft Visual C# 2005 - Schritt für Schritt, 2. Auflage - Sharp, John
      Ich besitze die erste deutsche Ausgabe dieses Buches welche offiziell von Microsoft Press unter dem englischen Namen Microsoft® Visual C#™ .NET Step by Step vertrieben wird. Dieses Buch gilt als absolutes Einsteigerbuch und behandelt auf sehr ausführliche und interessante Art und Weise die Programmiersprache C# unter der IDE Visual C#. In der ersten Package-Ausgabe wurde dem Käufer zusätzlich eine vollständige Vollversion von Visual C# .NET 2003 mitgeliefert. Die oben verlinkte Version ist ein indirekter Nachfolger der ersten Auflage, allerdings ohne das Softwarepaket Visual C#.
    • Programmieren mit C#, 2. Auflage - Jesse Liberty
      Behandelt so gut wie alle Themen zu den Sprachkonzepten von C# 2.0. Ist geeignet für Programmierer mit grundlegenden Kenntnissen in C++ oder auch Java. Gilt als Standardbuch für viele C# Programmierer und ist seit August 2005 auch in Deutsch erhältlich. Die deutsche 2. Auflage ist eine Übersetzung der amerikanischen 4. Auflage und sehr empfehlenswert.
    • Pro C# 2005 and the .NET 2.0 Platform, 3nd Edition - Andrew Troelsen
      Gilt bei vielen Entwicklern ebenfalls als eines der besten verfügbaren C#/.NET Bücher auf dem Markt. Deckt weite Bereiche inklusive Windows Forms, COM interop, ADO.NET, ASP.NET usw. ab.
    • Windows Programmierung mit C# - Charles Petzold
      Ein wenig irreführend ist der Titel. In seiner komplett neuen Auflage des Klassikers Windows-Programmierung, diesmal mit C#, behandelt der Windows Guru Charles Petzold weniger die Sprachkonzepte von C# als vielmehr Themen zur Windows GUI Programmierung. Windows Forms, Tastatuteingaben und GDI+, fast alles was das grafikverwöhnte Herz begehrt wird von diesem 1127 Seiten Wälzer behandelt. Das Buch ist ein Muss für C/C++ Programmierer. Einziger Kritikpunkt. Es behandelt nicht alle feinen 'Tips und Tricks' für echte reale Anwendungen. Dem Buch liegt eine CD bei.
    • Developing Applications with Visual Studio.NET - Richard Grimes
      Deckt viele interessante Bereiche ab, auf die andere Bücher oft nicht näher eingehen, inklusive ATL7, Managed C++, Internationalisierung, Remoting genauso wie natürlich allgemein CLR und C#. Außerdem viel zur Entwicklungsumgebung Visual Studio .NET. Dieses Buch ist gut geeignet für erfahrene C++ Programmierer.
    • Applied Microsoft .NET Framework Programming - Jeffrey Richter
      Wie aufgrund der exzellenten Win32 Bücher von Jeffrey Richter erwartet, sehr gut geschrieben. Das Anhängsel 'Applied' ist ein wenig irreführend, weil das Buch hauptsächlich das .NET Framework genauer unter die Lupe nimmt.
    Angehängte Dateien
Lädt...
X