C#4.0 – Problematik bei Default Values

Golo Roden erwähnte es bereits in den Kommentaren, daher möchte ich noch mal genauer darauf eingehen.
Dazu erstelle ich eine Solution in Visual Studio 2010 mit einer Konsolenapplikation, welche ich „DefaultValues“ nenne.

Die alte Schreibweise

Die Schreibweise unter C#3.0 mit Überladung wäre also in etwa so:

    public class Program
    {
        static void Main(string[] args)
        {

            AddValues("Ich bin ein", "String");
            Console.WriteLine(_value);

            AddValues("Ich bin ein", "String", true);

            Console.ReadLine();
        }

        public static string _value;

        public static void AddValues(string value1, string value2)
        {
            AddValues(value1, value2, false);
        }
        public static void AddValues(string value1, string value2, bool output)
        {
            _value = string.Format("{0} {1}", value1, value2);
            if(output)
            {
                Console.WriteLine(_value);
            }
        }
    }

Wenn wir nun das Projekt ausführen erhalten wir folgende Ausgabe.

Ich bin ein String
Ich bin ein String

Die erste Ausgabe erfolgt manuell, die zweite direkt in der Methode, wie gewünscht.

C#4.0 mit Default Values

Unter C#4.0 mit Default Values kann man die ganze Sache nun vereinfachen:

public static void AddValues(string value1, string value2, bool output = false)
{
    _value = string.Format("{0} {1}", value1, value2);
    if(output)
    {
        Console.WriteLine(_value);
    }
}

Die Ausgabe ist identisch. Die erste Zeile wird manuell ausgegeben, die zweite über den Methodenaufruf. Das macht die Sache einfach, spart Code, macht ihn leserlicher. Man findet sicherlich noch weitere Vorteile.

Das Problem erkennen

Kommen wir nun zu den Problemen. Bevor ich die erläutern kann, muss man wissen, wie C# die Default Values behandelt. Wenn man sich die Anwendung per Reflector ansieht, sieht man folgenden Code (in der C#-Ansicht):

private static void AddValues(string value1, string value2, [Optional, DefaultParameterValue(false)] bool output);

Die Zeile spricht für sich. Der Standardwert lautet „false“. Nun erstellen wir ein neues Projekt („TestApp“) und referenzieren auf unsere Methode mit dem Default Value:

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            DefaultValues.Program.AddValues("Ich bin ein", "String");
            Console.WriteLine(DefaultValues.Program._value);

            Console.ReadLine();
        }
    }
}

Ausgegben wird eine Zeile, wie erwartet, durch die manuelle Ausgabe. Nun sehen wir uns die zweite Exe-Datei mal im Reflector an:

Program.AddValues("Ich bin ein", "String", false);

Auf einmal sind drei Parameter vorhanden, obwohl wir nur zwei im Sourcecode angegeben haben. Der Compiler setzt automatisch den dritten Parameter mit dem Standardwert, in dem Fall false.
Nun ändern wir die AddValues()-Methode, die Ausgabe soll standardmäßig sofort in der Methode erfolgen, zudem ändern wir den String etwas:

public static void AddValues(string value1, string value2, bool output = true)
{
    _value = string.Format("Zusammengesetzt: {0} {1}", value1, value2);
    if (output)
    {
        Console.WriteLine(_value);
    }
}

Nun kompilier ich nur das Projekt „DefaultValues“ und kopiere die DefaultValues.exe in das Bin-Verzeichnis der TestApp. Wenn ich nun die TestApp.exe starte erhalte ich folgende Ausgabe:

Zusammengesetzt: Ich bin ein String

Allerdings haben wir den Standardwert für die Ausgabe auf true gesetzt, daher müsste die Ausgabe doppelt erscheinen, einmal direkt über den Methodenaufruf und einmal durch die manuelle Ausgabe.

Problem beheben

Dieses Problem resultiert daher, dass der Standardwert nicht „on-the-fly“ aus der DefaultValue.exe geholt wird, sondern vom Compiler in der TestApp.exe gesetzt wurde.
Die Methode aus der DefaultValues.exe wird also immer noch mit „AddValues(„Ich bin ein“, „String“, false);“ aufgerufen. Und so lange wir das TestApp-Projekt nicht neu kompilieren, wird sich an der Ausgabe nichts ändern.

Fazit

Default Values sind eine nette Sache, um sich Überladungen zu sparen, den Code leserlicher zu machen und dem Programmierer das Leben leichter. Aber eigentlich gibt es keine Default Value, der Compiler setzt einfach nur die Werte, die man vorher manuell gesetzt hat. Wenn man diesen Aspekt nicht vergisst, können DefaultValues eine schöne Sache sein, ansonsten sucht man sich wahrscheinlich dumm und dämlich, bis man den Fehler gefunden hat.

Vielen Dank hier noch mal an Oliver Sturm, welcher die Problematik auf der Basta kurz aber verständlich erklärt hat.

Beispielsolution: DefaultValues.zip

2 Gedanken zu „C#4.0 – Problematik bei Default Values“

  1. „Der Compiler setzt automatisch den dritten mit dem Default Value. Nun wollen wir die AddValues()-Methode ändern, die Ausgabe soll standardmäßig…“ – du hast hier nen kleinen fehler 🙂

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.