Einige Fragen zu C# als Umsteiger von C++



  • Seit einigen Wochen beschäftige ich mich nun schon mit C#, nachdem ich lange Zeit in C/C++ programmiert habe. Bis jetzt konnte ich aber gegenüber C++ eher nur Defizite erkennen, z.B.:

    1. keine const Methoden, die sicherstellen, dass Attribute einer Klasse nicht verändert werden dürfen, bzw. kann man auch Objekte nicht als const vereinbaren.
    2. Wenn ein Attribut einer Klasse ein Referenztyp ist, so wäre es gut, einen Kopierkonstruktor, bzw. überladenen Zuweisungsoperator zu erstellen, um die Möglichkeit zu haben, eine tiefe Kopie zu erstellen, ansonsten kann ich ja nur flach kopieren. Wie kann ich das im Bedarf bewerkstelligen?
    3. Ich kann ein in eine Klasse eingebettetes Objekt durch eine Methode nicht als konstante Referenz zurückgeben, wodurch das als private deklarierte Objekt dann ja beliebig ausserhalb der Klasse manipuliert werden kann. 😕
    4. Warum wird bei einer Struktur immer ein Satndarkonstruktor implizit erstellt? Vielleicht möchte ich ja einen Standardkonstruktor haben, der alle bool Datenelemente auf true setzt 😕
    5. Wo besteht die Logik darin, eine Objekt immer am Heap anzulegen???

    Und die Frage, die mich am meisten verwirrt:

    6. Eine Strukur kann ja (so habe ich gelesen und getestet) nicht von einer Klasse abgeleitet werden.
    Wie kommt es dann, dass die Strukturtypen Int.System32, etc. von object abgeleitet sind?

    Und noch was:

    7. Der Cast Operator in C-Syntax ist meiner Ansicht nach ein Rückschritt gegenüber static_cast und vor allem dynmic_cast aus C++.
    So weit ich weiss, wird nur eine InvalidCastException ausgelöst, wenn ein cast nicht durchgeführt werden kann, während dynamic_cast bei Zeigern dann einfacherweise einen Null Pointer retourniert.
    8. Und wenn ich in C# eine Collection verwende, so werden Objekte vom Typ object angelegt, wodurch IMMER ein Cast notwendig ist, wenn man indiziert.
    Wofür hab ich dann eine Schnittstelle, wenn ich vorher eh permanent casten muss?

    Viele fragen....

    Es würde mich an dieser Stelle echt mal interessieren, wie ihr das seht und ob ihr all diese Dinge auch als Nachteile betrachtet....

    Vielen Dank! 😉



  • Und gibt es in C# eigentlich eine View Klasse wie in MFC?
    Habe bis jetzt nur TreeView, etc. entdeckt....



  • SliderMax schrieb:

    7. Der Cast Operator in C-Syntax ist meiner Ansicht nach ein Rückschritt gegenüber static_cast und vor allem dynmic_cast aus C++.
    So weit ich weiss, wird nur eine InvalidCastException ausgelöst, wenn ein cast nicht durchgeführt werden kann, während dynamic_cast bei Zeigern dann einfacherweise einen Null Pointer retourniert.

    Eine InvalidCastException ist ein Vorteil gegenüber einem zurückgegebenen Null-Pointer. Wenn so ein Cast nicht klappt, dann ist das immer ein Programmierfehler, der behoben werden muss. Wenn du jetzt eine InvalidCastException bekommst, dann weißt du, was wo passiert ist, kannst den Fehler relativ schnell finden und beseitigen. Wenn ein Null-Pointer zurückgegeben wird, dann kann noch ne Menge Code durchlaufen, bis der Fehler wirklich ersichtlich wird. Der Fehler kann dann an einer ganz anderen Stelle auftreten und du weißt erstmal nicht, was eigentlich passiert ist und vor allem wo der Fehler wirklich aufgetreten ist. Du wirst lange suchen müssen, bis du die Fehlerquelle findest. Ein Null-Pointer kann ja vermutlich auch durch andere Dinge erzeugt werden, somit hast du keinen Anhaltspunkt, woran es eigentlich liegt.

    (Dieser Beitrag basiert auf der Annahme, dass es in C# ähnliche Informationen bei auftretenden Exceptions gibt, wie in Java.)



  • Zu der Frage

    . Warum wird bei einer Struktur immer ein Satndarkonstruktor implizit erstellt? Vielleicht möchte ich ja einen Standardkonstruktor haben, der alle bool Datenelemente auf true setzt

    Ich weiß nicht wie C Sharp das handhabt aber beim Visual Studio 6.0 war es einfach ein Fehler das du z.B:

    class Test
    {
    int b;
    };
    

    compilieren konntest. Normalerweise hätte der Compilern meckern müssen das kein Standardkonstruktor zur Verfügung steht. Bei C# hoffe und denke ich das die das geändert haben, d.h. wenn du keinen Standardkonstruktor implementierst müsste das der Compilter machen.



  • dfgdfgdf:

    Die Klasse, die du gerschrieben hast, hat in C++ einen Standardkonstruktor, aber mit leerem Anweisungsteil, während der Standardkonstruktor in C# die Variable b aud 0 setzen würde.

    Gregor:

    Wenn so ein Cast nicht klappt, dann ist das immer ein Programmierfehler, der behoben werden muss.

    Nein, dem ist nicht so. Durch den Null Zeiger kann man auch festellen, ob ein Basisklassenzeiger auf ein abgeleitetes Objekt verweist, z.b.

    if(dynamic_cast<Derived*>(pointer))
             pointer->MethodeFürAbgeleiteteKlasse();
    


  • SliderMax schrieb:

    2. tiefe Kopie

    Schau Dir mal das ICloneable-Interface an.

    SliderMax schrieb:

    4. Warum wird bei einer Struktur immer ein Satndarkonstruktor implizit erstellt?

    Oh, das war mir bisher entgangen. Das ist in der Tat abartig! Der Standard-Konstruktor wird zwar in C++ auch automatisch angelegt, aber daß man ihn in c# nicht selbst definieren kann ... 😕

    SliderMax schrieb:

    8. Und wenn ich in C# eine Collection verwende, so werden Objekte vom Typ object angelegt, wodurch IMMER ein Cast notwendig ist, wenn man indiziert.
    Wofür hab ich dann eine Schnittstelle, wenn ich vorher eh permanent casten muss?

    Ich bin nicht sicher, wo das Problem ist, welche Schnittstelle meinst Du? Collection ist nun mal ein generischer Typ und speichert stets object-Referenzen. Für Typ-sichere Container-Klassen könntest Du eine eigene Klasse schreiben und die IList-Schnittstelle implementieren. Abgesehen davon gibt es in c# noch die Möglichkeit, die Klassenzugehörigkeit zu überprüfen (is-Operator) bzw. dynamic_cast-ähnliche Umwandlungen vorzunehmen (as-Operator).



  • SliderMax schrieb:

    Wenn so ein Cast nicht klappt, dann ist das immer ein Programmierfehler, der behoben werden muss.

    Nein, dem ist nicht so. Durch den Null Zeiger kann man auch festellen, ob ein Basisklassenzeiger auf ein abgeleitetes Objekt verweist, z.b.

    if(dynamic_cast<Derived*>(pointer))
             pointer->MethodeFürAbgeleiteteKlasse();
    

    Für solche Dinge gibt es explizite Sprachmittel in C#. Insofern würde ich es als ne Art Bad-Style-Beispiel ansehen, wenn du soetwas so in C# versuchen würdest. Es ist somit gut, dass das so nicht geht.



  • Für solche Dinge gibt es explizite Sprachmittel in C#.

    Genau, und eines davon hat die Semantik wie dynamic_cast.

    - in Java gibt es instanceof

    - in C# gibt is
    -- is - so wie instanceof in Java
    -- as - so wie dynamic_cast

    String blubberstring = myObject as String;   // blubberstring ist null, wenn das Objekt kein String ist.
    
    bool isAString = myObject is String;   // ma schaun, ob das ein String ist...
    

    Ich glaube, der as-operator ist das, was Max gesucht hat.
    Das casts Exceptions werfen, muss auch so sein. Ein cast (String) ist nicht dafür da, um irgendwas zu testen.
    Ein cast sollte *niemals* schiefgehen.



  • Ach, da waren ja noch ein paar Fragen mehr. 😃

    1. Nein. Das Konzept ist bei C# (und Java) ein anderes. Man versucht, immutable Klassen zu schaffen, bei denen man dann auch gefahrlos Referenzen zuweisen kann, um eigentlich einen Wert zuzuweisen. Man erspart sich damit sogar die Erstellung eines neuen Objekts.
    Methoden geben neue Objekte zurück.

    string x = "  abc  ";   // x referenziert "  abc  "
    string y = x.Trim();  // y referenziert einen _neuen_ string "abc"
    // x referenziert immer noch den alten, der unverändert ist.
    

    Ist nicht immer ein gleichwertiger Ersatz für const, aber unkomplizierter. Das einzige Problem bei dieser Vorgehensweise wäre die Speicherverwaltung, was natürlich in C# nicht existent ist.

    class Foo
    {
        // Kopierkonstruktor:
        Foo(Foo original)
        {
        }
    
        // Wird dynamisch gebunden!! Sollte base.Clone() aufrufen
        object Clone()
        {
        }
    }
    

    3. Es ist generell schlechter Stil, Referenzen auf interne Daten zurückzugeben, auch in C++, auch mit const.

    4. Das ist halt ein dummes struct. Du kannst einen eigenen Konstruktor erstellen, aber keinen eigenen Standardkonstruktor. Im Grunde ist ein struct nur eine Sammlung von lokalen Variablen. Für diese wird halt jeweils der Standardkonstruktor aufgerufen, wenn du den vom struct aufrufst.

    5. Ist doch sauschnell. Geht fast so schnell wie auf dem Stack. Die Allokierung von Speicher funktioniert auf einem managed Heap völlig anders.
    structs liegen übrigens auf dem Stack.

    6. Das ist das Geheimnis von Microsoft. Du sollst ein struct als Objekt behandeln dürfen. Da bei structs jedoch keine Typinformationen vorliegen, kein vtbl oder sonst irgendwas, kannste Vererbung damit mehr oder weniger vergessen, Polymorphie ist nicht möglich.
    structs sind nur dumme Sammlungen von lokalen Variablen.

    7. Ist ja hoffentlich geklärt.

    Ich hoffe, ein wenig Licht ins Dunkel gebracht zu haben. 🤡 👍



  • Ja, Vielen Dank!


Anmelden zum Antworten