2010-04-30 12 views
5

Der folgende Code kann nicht kompiliert werden und erzeugt einen Fehler "Widget muss ein nicht-abstrakter Typ mit einem öffentlichen parameterlosen Konstruktor sein". Ich würde denken, dass der Compiler alle Informationen hat, die er benötigt. Ist das ein Fehler? Ein Versehen? Oder gibt es ein Szenario, in dem dies nicht gelten würde?Warum wird die neue() generische Bedingung nicht durch eine Klasse mit optionalen Parametern im Konstruktor erfüllt?

+0

Paging Eric Lippert .... Ich denke, das wird auf optionale Parameter als eine Compiler-Funktion, aber allgemeine Einschränkungen als CLR sein. So werden optionale Parameter durch den Compiler ersetzt, und das JIT sieht nur (requied) Parameter. – Richard

+0

@Richard: Das ist im Grunde das Problem hier. Optionale Parameter haben auch einige seltsame Nebenwirkungen für die Versionierung. Genau aus diesem Grund ... –

Antwort

7

Während dies logisch funktionieren sollte, tut es leider nicht. Die CLR sieht Ihren Konstruktor immer noch als einen Parameter-basierten Konstruktor.

Denken Sie daran, dass, während C# optionale Parameter unterstützt, dies auf Compiler-Ebene zur Kompilierzeit geschieht. Der zugrunde liegende Typ enthält immer noch nur einen Konstruktor, der einen einzelnen Parameter verwendet. Soweit die CLR betrifft, wird der "default parameter" auf Attribute umgewandelt, etwa so:

public Widget(([Optional, DefaultParameterValue("foo")] string name) { // ... 

Die CLR ist eine Multi-Language Runtime. Generics sind für alle Sprachen auf CLR-Ebene ausgelegt, sodass die Einschränkungen auch in Sprachen ohne Standardparameter erfüllt sein müssen. Sprachen sind nicht erforderlich, um das OptionalAttribute oder das DefaultParameterValueAttribute zu verstehen, daher kann dies nicht für alle Sprachen einheitlich funktionieren, daher ist es nicht zulässig.


Edit:

Als Antwort auf Ihren Kommentar:

Was ich nicht verstehe ist, warum der C# -Compiler den erforderlichen Code nicht generieren kann die CLR

zu befriedigen

Theoretisch könnte das C# -Compiler-Team die Sprache zwei separate Konstruktoren anstelle eines Konstruktors mit Attributen generieren lassen. Dies würde möglicherweise in viele Konstruktoren explodieren, da benannte Parameter die Fähigkeiten für viele, viele mögliche Kombinationen von "Konstruktoren" (oder Methodenaufrufen für Methoden) erzeugen, insbesondere wenn mehrere Argumente verfügbar sind. Ich persönlich bin froh, dass dies nicht der Fall war, da es aufgrund der vielen Methoden und Konstruktoren in den generierten Typen zu Verwirrung führen würde, was dazu führen würde, dass die öffentliche API sehr anders aussieht als der Code, der sie generiert hat. Nehmen Sie den folgenden Konstruktor:

public Widget(
      int id = 0, 
      string name = "foo", 
      float width=1.0f, 
      float height=1.0f, 
      float depth=1.0f 
     ) { // ... 

Waren Sie automatisch alle möglichen Kombinationen hier zu generieren, müsste der Compiler Konstrukteure für diesen einzelnen Konstruktor erzeugen, da es N sind! mögliche Wege, dies zu nennen ...

+0

@Joshua: Der C# -Compiler erzeugt den Code, den ich oben eingefügt habe. So funktioniert es - es wird kein parameterloser Konstruktor erstellt, sondern ein optionaler Konstruktor. Ich werde bearbeiten, um Details hinzuzufügen ... –

+0

Ok, danke, das erklärt, warum es nicht funktioniert. Ich frage mich immer noch, welche Auswirkungen die Generierung des parameterlosen Konstruktors hätte. –

+0

@Joshua: Ich habe meine Antwort bearbeitet, um zu erklären, warum das möglicherweise eine schlechte Idee ist ... Machen Sie jetzt mehr Sinn? Denken Sie daran, es ist nicht nur optional, Sie können auch benannte Parameter verwenden, also bedeutet N Parameter N! mögliche Kombinationen, die generiert werden müssten ... –