Site logo
Site logo
Programmieren aus Leidenschaft
Programmieren aus Leidenschaft

Felder und Eigenschaften


Mein Anspruch, wenig C#-Grundlagen zu erklären, wird mit folgendem Kapitel schon widerlegt. Denn streng genommen sind Felder und Eigenschaften C#-Grundlagen und sogar sehr wichtige. Das ich es trotzdem erkläre, mag daran liegen, dass ich sehr oft mit Menschen zusammen arbeite, die ursprünglich eine andere Programmiersprache gelernt haben, bei der es das Prinzip der Felder und Eigenschaften in dieser Form nicht gab. Deshalb hier jetzt ein kleiner Einblick:

Oftmals braucht man Klassen um zusammengehörige Daten zu speichern. Früher haben wir Klassen wie diese gebaut:

public class WerteKlasse
{
   public string name;
   public string vorname;
   public int alter;
}


Das sollte jedem der schon mal in einer objektorientierten Sprache programmiert hat bekannt vorkommen. Wir haben hier drei Variablen (auch Felder genannt), zwei string (Zeichenkette) und ein int (Ganzzahl). Diese Variablen sind als "public" deklariert, denn man will ja auch darauf zugreifen. Das ging dann in etwas so:

WerteKlasse meineWerte = new WerteKlasse();

meineWerte.name = "Meier";
meineWerte.vorname = "Max";
meineWerte.alter = 32;


Von der Klasse erzeugen wir ein Objekt (meineWerte), in dessen Felder wir unsere Werte schreiben können. Schon immer so gemacht, ich hoffe ich erzähle hier nichts Neues. Das funktioniert auch immer noch einwandfrei. Aber die Zeiten ändern sich, in C# kann das Ganze etwas anders aussehen:

public class WerteKlasse
{
   private string _name;
   public string name
   {
      get { return _name; }
      set { _name = value; }
   }

   private string _vorname;
   public string vorname
   {
      get { return _vorname; }
      set { _vorname = value; }
   }

   private int _alter;
   public int alter
   {
      get { return _alter; }
      set { _alter = value; }
   }
}


Auch hier haben wir noch den "public string name", aber irgendwie sieht das gar nicht mehr wie eine Variable aus, sondern mehr wie eine Methode. Und das ist es im Prinzip auch fast und es hat die Bezeichnung "Eigenschaft" (eng. Property). Die Werte werden nicht mehr in Public-Feldern gespeichert, sondern in privaten Feldern die von außerhalb der Klasse nicht zugänglich sind. Gehandhabt wird dieses Verfahren über die get- und set-Methoden und über "value". Natürlich ist es kein Zwang, dass das private Gegenstück zu name unbedingt _name heißen muß. Die Bezeichnung ist frei wählbar, aber ich habe mir diese Art der Namensgebung angewöhnt und kann sie nur empfehlen.

Fassen wir noch mal zusammen: Wenn ich

meineWerte.name = "Meier";

aufrufe, so schreibe ich nicht in ein Public-Feld, sondern rufe eine Eigenschaft auf, die meinen Wert in ein Private-Feld schreibt. Für ein Public-Feld eignet sich die set-Methode. Will ich hingegen meinen Wert wieder auslesen wird die get-Methode benutzt.

Um ehrlich zu sein, habe ich mich anfangs auch gefragt, was der ganze Aufwand soll, als ich diese Art der Klassen zum ersten Mal gesehen habe. Nicht viel - könnte man meinen und das mag stimmen. Aber es wird gleich interessanter, denn wir können in den get- und set-Methoden auch noch eigenen Programmcode unterbringen. Fangen wir mit etwas ganz einfachem an:

private string _name;
public string name
{
   get { return _name; }
   set { _name = value.Trim(); }
}


Wer kennt das nicht? Überflüssige Leerzeichen bei Zeichenketten, vor allem wenn sie aus Texteingabefeldern kommen. Die können einem Programmierer schon das Leben schwer machen, wenn man Texte vergleicht oder die Anzahl der Zeichen wichtig sind. Trim entfernt zwar führende und nachfolgende Leerzeichen, doch leider wird der Befehl viel zu oft vergessen. Jetzt nicht mehr. Alleine durch value.Trim() ist es nicht mehr möglich überflüssige Leerzeichen im Namen zu haben. Und dieser Befehl wird immer ausgeführt, wenn ich einen Wert speichere. Immer! Es geht nicht mehr ohne, man kann nie wieder vergessen Leerzeichen zu entfernen.

Nächstes Beispiel:

private int _alter;
public int alter
{
    get { return _alter; }
   set {
   if (value < 0)
   value = 0;
   _alter = value;
   }
}


Wie man sieht kann ich value auch vergleichen. Hier ist es zum Beispiel nicht möglich ein negatives Alter zu speichern.
Richtig interessant wird es aber erst, wenn ich eine der Methoden weglassen:

private string _name;
public string name
{
   set { _name = value.Trim(); }
}


Warum soll das nicht funktionieren? Ich kann weiterhin Werte speichern. Versuche, diesen Wert dann wieder auszulesen, schlagen allerdings fehl.

WerteKlasse meineWerte = new WerteKlasse();

meineWerte.name = "Meier";
MessageBox.Show(meineWerte.name);


Dieses Programm wird schon während des Erstellens vom Compiler als fehlerhaft erkannt, weil ich "meineWerte.name" eben nicht in einer Messagebox ausgeben kann. Der gespeicherte Wert ist für mich nicht erreichbar. Wollen wir ihn wirklich auslesen, brauchen wir dafür eine Methode in unserer Werte-Klasse.

public string nameAusgeben()
{
   return _name;
}


Anzeigen kann man denn Namen dann wie folgt:

MessageBox.Show(meineWerte.nameAusgeben());

Ebenfalls möglich ist es die set-Methode wegzulassen. Eine eigene Methode, mit der man den Wert dann trotzdem setzen kann, sähe dann so aus:

public void namenSpeichern(string name)
{
   this._name = name;
}


Es ist bei komplexen Klassen nicht ungewöhnlich, dass man interne Werte gar nicht mehr direkt beeinflussen kann, sondern nur über dafür vorgesehen Methoden. Ein solches Vorgehen trägt, wenn es richtig ausgeführt wird, sehr zur Betriebssicherheit des Programmes bei, indem man grundsätzlich logisch oder technisch falsche Werte in den Klassen verhindert und den Zugriff einschränkt.