Welcher Constructor wird aufgerufen?

Image courtesy of "artur84" / FreeDigitalPhotos.net

Image courtesy of „artur84“ / FreeDigitalPhotos.net

Seit der Version 4.0 sind in C# Methoden mit Parametern erlaubt, die einen Default-Wert besitzen. Dies kann auch auf Contructor-Methoden angewendet werden, also z.B.

1
2
3
4
5
6
7
8
9
10
11
12
public class A
{
  public A()
  {
    // ...
  }
 
  public A(string x = "default")
  {
    // ...
  }
}

Die Frage ist nun: Welcher Constructor wird verwendet, wenn ich eine Instanz mit A a = new A(); erzeuge?

Versuch 1

Im oben beschriebenen Fall kann dies schnell beantwortet werden, indem man es einfach ausprobiert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace ConstructorQuiz1
{
  class Program
  {
    static void Main(string[] args)
    {
      A a1 = new A();
      A a2 = new A("fix");
    }
  }
 
  public class A
  {
    public A()
    {
      System.Console.WriteLine("A()");
    }
 
    public A(string x = "default")
    {
      System.Console.WriteLine(x);
    }
  }
}

Und hier das Resultat:

A()
fix

Man sieht also, dass der „am besten passende“ Constructor verwendet wird und der Default-Wert keine Verwendung findet. (wenn der Standard-Constructor A() nicht existieren würde, würde natürlich der Default-Wert verwendet).

Versuch 2

Wenn man aber mit den Access Modifiers herumspielt ist das ganze nicht mehr so eindeutig. Setzen wir einmal den Access Modifier des Standard-Constructors auf internal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace ConstructorQuiz2
{
  class Program
  {
    static void Main(string[] args)
    {
      A a1 = new A();
      A a2 = new A("fix");
    }
  }
 
  public class A
  {
    internal A()
    {
      System.Console.WriteLine("A()");
    }
 
    public A(string x = "default")
    {
      System.Console.WriteLine(x);
    }
  }
}

Das Ergebnis ist immer noch das selbe, hier hat der geänderte Access Modifier also noch keine Wirkung gezeigt.

Versuch 3

Versuchen wir jetzt aber mal von Aussen zuzugreifen:

1
2
3
4
5
6
7
8
9
10
11
namespace ConstructorQuiz3
{
  class Program
  {
    static void Main(string[] args)
    {
      ConstructorQuiz2.A a1 = new ConstructorQuiz2.A();
      ConstructorQuiz2.A a2 = new ConstructorQuiz2.A("fix");
    }
  }
}

Dieser Code muss mit einer Referenz auf den compilierten Code aus dem zweiten Beispiel enthalten. Dies erfolgt beim Command Line Tool csc mit dem Parameter /r=<filename>.

Das Resultat sieht nun anders aus:

default
fix

Es wird jetzt also der Constructor mit dem Default-Wert aufgerufen, da der Standard-Constructor von der Dritt-Assembly nicht aufgerufen werden darf.

Fazit

Wann welcher Constructor verwendet wird ist nicht nur von den Parametern sondern auch von den Access Modifiern und dem Kontext abhängig.

Schreibe einen Kommentar

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