Archiv für September 2008

C driven C#

Mittwoch, 24. September 2008

Alte Gewohnheiten wird man oft nicht los, auch wenn es längst keinen Grund mehr gibt daran festzuhalten. So habe ich z.B. folgendes Konstrukt in unserem C#-Code gefunden, welches offensichtlich von einem eingefleischten C++ Programmierer kommt:

ClassA a = new ClassA();
if( a != null )
{
   …
}

Was in C++ noch Richtig war, ist in C# in dieser Art und Weise einfach Unsinn. In C++ konnte es natürlich passieren, wenn es keinen Speicher mehr gab, das der new-Operator als Ergebnis “NULL” lieferte. In C# jedoch wird in diesem Fall eine Exception “geschmissen”. Genauer gesagt die OutOfMemoryException. Was leicht in der MSDN nachgelesen werden kann. Sollte einem C/C++ Programmierer immer noch ein ungütes Gefühl beschleichen, steht einem ja ein Blick in die C#-Language-Specification offen, die ja bei Microsoft runtergeladen werden kann. Für die Sprachversion 1.2 ist im Kapitel 7.5.10.1 folgendes zu lesen:

AIf there is not enough memory available to allocate the new instance, a System.OutOfMemoryExceptionis thrown and no further steps are executed

Dort steht es also schwarz auf weiss. Sogar noch mit dem Hinweis, das keine Anweisung nach dem new Ausgeführt werden (was ja ein wesentlicher Teil des Exception-Handlings ist). Somit kann getrost auf die if-Abfrage verzichtet werden. Möchte man wirklich überprüfen ob nicht genug Speicher vorhanden war, kann man wie gewohnt mit try/catch die Exception abfangen. Über die Sinnhaftigkeit lässt sich vortrefflich streiten. Dies würde aber diesen Eintrag sprengen und muss nochmal an anderer Stelle etwas ausführlicher Diskutiert werden.

Bin ich noch null oder was?

Mittwoch, 24. September 2008

Da ich ja wieder mit einem Code-Review “beauftragt” wurde, mussten ja wieder Dinge für Coding-Horror abfallen. So wie auch folgendes kleines C# Konstrukt. Habe wieder alles Unnötige weggelassen. Man betrachte folgende kleine Klasse:

Image

Die Klassenvariable obj wird zuerst mit null initalisiert. Im Konstruktor wird dann überprüft, ob obj schon auf ein Objekt referenziert und wenn nicht, wird eine Instanz angelegt. Wenn wir mal in die C#-Language-Spezifikation sehen, steht dort was beim Instanziieren einer Klasse (Referenced-Type) passiert.

- A new instance of class T is allocated. If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.

- All fields of the new instance are initialized to their default values (§?5.2).

- The instance constructor is invoked according to the rules of function member invocation (§?7.4.3). A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor as this.

Gehen wir also davon aus, das wir genug Speicher hatten und das Objekt tatsächlich angelegt werden konnte. Dann kann man dort nachlesen, das zuerst die Membervariablen (Fields) initialisiert werden. Das heisst in unserem Beispiel, das die Variable obj mit null Initialisiert wird (was auch defaultmässig passieren würde, wenn man das “= null“ weglässt) bevor der Konstruktor aufgerufen wird. Danach folgt gleich der Konstruktoraufruf. Dort wird dann auf null überprüft, was obj wie wir ja jetzt wissen “zwingend” sein muss. Somit ist diese Überprüfung im Konstruktor völlig seinfrei.

Die Initalisierung von obj kann also direkt in der Klasse erfolgen:

Dieses vorgehen hat aber einen Haken. Wenn die anzulegende Klasse (hier object) eine Exception schmeisst und diese in der eigenen Klasse (ObjectMania) abgefangen werden soll. Dann muss die Instanziierung im Konstruktor erfolgen:

Abschliessend nochmal zur Frage, ob es sinvoll ist obj mit null vorzubelegen. Im Prinzip wäre es egal, da alle neue Referenzen den Wert null haben. Von Microsoft wird jedoch empfolen, Variablen stets mit einem Defaultwert zu initalisieren (MCTS Kurs: 70-536).