CodeGym /Kurse /C# SELF /Häufige Fehler beim Deklarieren von Klassen und Objekten

Häufige Fehler beim Deklarieren von Klassen und Objekten

C# SELF
Level 25, Lektion 0
Verfügbar

1. Problem mit gleichen Namen: Feld, Property, Parameter

Anfänger stolpern oft darüber, dass Property-Namen, Konstruktor-Parameter und private Felder gleich heißen. Der Compiler meckert zwar nicht, aber das Ergebnis ist oft nicht das, was du erwartest.

Beispiel

public class Student
{
    private string name;

    public Student(string name)
    {
        name = name; // "Sieht richtig aus, oder?"
    }

    public void PrintName()
    {
        Console.WriteLine(name);
    }
}

Was passiert? Die Methode PrintName() hat nichts zum Ausgeben: Das private Feld name bleibt null! Das liegt daran, dass im Konstruktor name = name; nur mit dem lokalen Parameter gearbeitet wird, nicht mit dem Feld der Klasse.

Wie vermeiden

Benutze das Schlüsselwort this, um auf Felder/Properties der Klasse zuzugreifen:

public Student(string name)
{
    this.name = name; // Jetzt passt's!
}

Hinweis: Rider und andere IDEs helfen dir, solche Fehler zu erkennen – ignorier ihre Hinweise nicht!

2. Kein Standardkonstruktor: Wann braucht man ihn?

Wenn du mindestens einen eigenen Konstruktor deklarierst, erstellt der Compiler keinen "leeren" Standardkonstruktor mehr. Das führt oft zu Fehlern, besonders wenn du ein Objekt ohne Parameter erzeugen willst.

Beispiel

public class Book
{
    public string Title { get; set; }

    // Explizit deklarierter Konstruktor
    public Book(string title)
    {
        Title = title;
    }
}

var book = new Book(); // Compiler: "Beep-beep! Kein parameterloser Konstruktor!"

Wenn du Instanzen sowohl mit als auch ohne Parameter erzeugen willst, vergiss nicht, den passenden Konstruktor explizit hinzuzufügen:

public Book() { }

public Book(string title)
{
    Title = title;
}

3. Zugriffsmodifikatoren: Privates Leben öffentlicher Leute

Ein häufiger Anfängerfehler: Nicht über Zugriffsmodifikatoren nachdenken. Standardmäßig sind Felder und Methoden einer Klasse private, und auch Struct-Mitglieder sind private. Unachtsamkeit oder Vergessen kann dazu führen, dass du gewünschte Properties oder Methoden außerhalb der Klasse nicht nutzen kannst.

Beispiel

public class Animal
{
    string name; // standardmäßig private

    public void PrintName()
    {
        Console.WriteLine(name);
    }
}

var animal = new Animal();
animal.name = "Barsik"; // Compilerfehler!

Der Compiler lässt keinen Zugriff auf private Mitglieder zu. Besser ist es, den Modifikator explizit anzugeben:

public string Name;

oder

private string name;

Für besseren Zugriff nutze Properties:

public string Name { get; set; }

4. Feld nicht initialisiert: null-Falle

Sehr verbreitete Falle – ein Feld der Klasse ist nicht initialisiert. Besonders kritisch, wenn das Feld in Methoden verwendet wird, die vor der expliziten Initialisierung aufgerufen werden.

Beispiel

public class Cat
{
    public string Name;

    public void SayHello()
    {
        Console.WriteLine($"Miau! Die Länge des Namens ist {Name.Length} Buchstaben!"); // Mögliches NullReferenceException
    }
}

var cat = new Cat();
cat.SayHello(); // Was für eine Tragödie!

Die Variable Name ist null, und der Versuch, auf Length zuzugreifen, führt zu NullReferenceException. Achte besonders auf den Zustand von Objekten nach der Erstellung!

Tipp: Nutze Konstruktoren, um wichtige Felder zwingend zu setzen, und markiere Properties als erforderlich (in neuem C# – mit required).

5. Endlose Rekursion in Auto-Properties: Copy-Paste-Fehler

Manchmal schreibt man ein Property von Hand und macht einen Fehler – zum Beispiel, wenn man im Getter oder Setter auf sich selbst zugreift (statt auf ein privates Feld), was zu einer Endlosschleife führt.

Beispiel

public class Dog
{
    public int Age
    {
        get { return Age; } // Ups!
        set { Age = value; } // Doppelt-Ups!
    }
}

Solcher Code ruft bei jedem Zugriff auf Age sich selbst auf... bis der Stack voll ist – rekursives Selbstfressen.

Richtig so

Benutze ein separates privates Feld:

private int age;

public int Age
{
    get { return age; }
    set { age = value; }
}

Oder nutze ein Auto-Property:

public int Age { get; set; }

6. Inkonsistente Namen

Im Programmieren ist Genauigkeit bei Groß-/Kleinschreibung und Namen wichtig. C# ist Case-Sensitive, und Name, name, NAME sind drei verschiedene Bezeichner.

Wenn du einen Feld- oder Property-Namen änderst, achte darauf, ihn überall zu ändern! Rider hilft beim Refactoring, aber Tippfehler (vor allem bei ähnlichen Namen) passieren trotzdem.

7. Falscher Modifikator (static/instance) verwendet

Manchmal verwechseln Anfänger Instanzmethoden und statische Methoden. Das Problem tritt auf, wenn du auf ein Feld/eine Methode zugreifen willst, wie es die C#-Syntax nicht erlaubt.

Beispiel

public class MathHelper
{
    public static int Add(int a, int b) => a + b;
    public int Multiply(int a, int b) => a * b;
}

var sum = MathHelper.Add(2, 3); // OK
var mul = MathHelper.Multiply(2, 3); // Fehler! 

Die Methode Multiply ist nicht statisch, sie kann nicht über den Klassennamen ohne Objekt aufgerufen werden:

var helper = new MathHelper();
var mul = helper.Multiply(2, 3); // Jetzt passt's

8. Fehler beim Vererben von Konstruktoren

Wenn deine Klasse von einer anderen Klasse erbt, vergiss nicht, dass die Basisklasse evtl. Parameter für ihren Konstruktor verlangt.

Beispiel

public class Animal
{
    public string Name;

    public Animal(string name)
    {
        Name = name;
    }
}

public class Dog : Animal
{
    public Dog() { } // Fehler: Basisklasse verlangt name!
}

Der Compiler lässt so einen Konstruktor nicht zu. Du musst explizit den Basisklassen-Konstruktor aufrufen:

public class Dog : Animal
{
    public Dog(string name) : base(name) { }
}

9. Nicht alle Interface-Mitglieder implementiert

Wenn deine Klasse ein Interface implementiert, aber nicht alle Methoden davon – bekommst du einen Compilerfehler: "Klasse implementiert Interface nicht vollständig".

Beispiel

public interface IWalker
{
    void Walk();
    void Run();
}

public class Turtle : IWalker
{
    public void Walk()
    {
        Console.WriteLine("Langsam und sicher...");
    }
    // Ups! Run vergessen!
}

Die IDE meckert, und Turtle lässt sich nicht kompilieren, bis du alle Methoden des Interfaces implementierst.

10. Verwendung von nicht initialisierten Objekten

In C# werden Objekte explizit mit new erzeugt. Wenn du nur eine Referenzvariable deklarierst, ihr aber kein Objekt zuweist – ist sie null. Beim Zugriff auf Felder/Methoden bekommst du den berühmten NullReferenceException.

Beispiel

Student student;
student.PrintName(); // Überraschung!

Du musst das Objekt unbedingt initialisieren:

Student student = new Student("Vasilisa");
student.PrintName();

11. Fehler: public Felder statt Properties

Alter "Anti-Pattern": Alle Felder der Klasse als public deklarieren. Warum ist das schlecht? Felder sind ungeschützt, keine Kontrolle über Änderungen, Kapselung ist futsch!

Beispiel

public class Car
{
    public int speed; // Mach das nicht!
}

Besser Properties verwenden:

public class Car
{
    public int Speed { get; set; }
}

Properties erlauben dir, Prüfungen, Logik, Einschränkungen hinzuzufügen:

private int speed;
public int Speed
{
    get { return speed; }
    set
    {
        if (value < 0) speed = 0;
        else speed = value;
    }
}

12. Implizite "magische Zahlen" oder Strings

Wenn du im Code 42, "Ivan", "SomeFile.txt" und andere "magische" Werte direkt in Methoden siehst – das ist potenziell ein Fehler. Besser Konstanten oder Felder verwenden.

Beispiel

public class ConfigManager
{
    public void Save()
    {
        File.WriteAllText("config.txt", "some data"); // Magischer String!
    }
}

Besser so:

public class ConfigManager
{
    private const string ConfigFileName = "config.txt";
    public void Save()
    {
        File.WriteAllText(ConfigFileName, "some data");
    }
}

13. Kopierfehler: Referenzvariablen auf dasselbe Objekt

In C# sind Objektvariablen Referenzen. Das Zuweisen einer Variablen zu einer anderen kopiert nur die Referenz, nicht das Objekt selbst. Das führt oft zu "plötzlichen" Änderungen.

Beispiel

Student s1 = new Student("Vasya");
Student s2 = s1;
s1.Name = "Kolya";
Console.WriteLine(s2.Name); // Gibt "Kolya" aus!

Warum? Weil s1 und s2 zwei Referenzen auf dasselbe Objekt sind!

14. Keine Rückmeldung bei Fehlern

Schlecht, wenn eine Klasse das Setzen ungültiger Werte erlaubt. Zum Beispiel ein negatives Alter.

Beispiel

public class Human
{
    public int Age { get; set; }
}

var h = new Human();
h.Age = -50; // Kein Problem...

Die Logik der Klasse sollte unsinnige Werte verhindern:

private int age;
public int Age
{
    get { return age; }
    set
    {
        if (value < 0)
            throw new ArgumentException("Alter darf nicht negativ sein.");
        age = value;
    }
}

15. Verwirrung beim Gültigkeitsbereich (scope)

Manchmal werden Variablen mit gleichem Namen in verschiedenen Gültigkeitsbereichen deklariert – innerhalb einer Methode und als Feld der Klasse.

Beispiel

public class MyClass
{
    int value = 10;

    public void Foo()
    {
        int value = 99;
        Console.WriteLine(value); // Gibt 99 aus, nicht 10!
    }
}

Um eindeutig auf das Feld der Klasse zuzugreifen, benutze this.value.

16. Methoden überschreiben ohne override

Wenn du eine virtuelle Methode der Basisklasse überschreiben willst, vergiss nicht das override!

Beispiel

public class Animal
{
    public virtual void Speak() => Console.WriteLine("Tier spricht");
}

public class Cat : Animal
{
    public void Speak() => Console.WriteLine("Miau!"); // Kein override!
}

Hier wird die Methode der Basisklasse nicht überschrieben: Die neue Methode versteckt die alte nur (shadowing), was zu Überraschungen bei Basisklassen-Referenzen führen kann.

Richtig:

public override void Speak() => Console.WriteLine("Miau!");

17. Virtuelle Methode im Konstruktor aufrufen

Das ist kein Compilerfehler, führt aber oft zu schwer auffindbaren Bugs. Wenn im Konstruktor der Basisklasse eine virtuelle Methode aufgerufen wird, die in der abgeleiteten Klasse überschrieben ist – können beim Aufruf Felder der Kindklasse noch nicht initialisiert sein.

Beispiel

public class Animal
{
    public Animal()
    {
        Speak();
    }

    public virtual void Speak()
    {
        Console.WriteLine("Tier...");
    }
}

public class Cat : Animal
{
    public string Name { get; set; } = "Barsik";

    public override void Speak()
    {
        Console.WriteLine($"Miau! Ich bin {Name}");
    }
}

Cat cat = new Cat();
// Beim Aufruf von Speak() ist der Cat-Konstruktor noch NICHT durchgelaufen, Name ist noch null!

18. Objekt nur über Konstruktor beschreiben (ohne Properties)

Wenn eine Klasse nur einen Konstruktor hat und das Objekt nach der Erstellung nicht mehr geändert werden kann – gut für unveränderliche Objekte, aber nicht immer praktisch. Meistens ist es besser, dem Nutzer der Klasse zu erlauben, Properties (oder zumindest einige davon) zu ändern.

19. Ignorieren von Standard-Namenskonventionen (naming conventions)

Klassennamen beginnen mit Großbuchstaben, Methoden auch, Felder mit kleinem Buchstaben und Unterstrich (oder camelCase), Konstanten – ALLES GROSS. Einheitlicher Stil verbessert nicht nur die Lesbarkeit, sondern senkt auch das Risiko von Fehlern!

20. Nicht verwendete Felder und Methoden

Wenn du ein Feld hast, das nirgends verwendet wird – das ist "toter Code". Die IDE kann dir solche Fälle anzeigen. Je weniger "tote Zonen", desto einfacher ist die Wartung der Anwendung!

2
Aufgabe
C# SELF, Level 25, Lektion 0
Gesperrt
Behebung des Fehlers mit identischen Namen und Verwendung des Schlüsselworts `this`
Behebung des Fehlers mit identischen Namen und Verwendung des Schlüsselworts `this`
2
Aufgabe
C# SELF, Level 25, Lektion 0
Gesperrt
Hinzufügen eines Standardkonstruktors
Hinzufügen eines Standardkonstruktors
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION