2008-09-05 12 views
44

C# benötigen Sie keine generischen Typparameter angeben, ob der Compiler es zum Beispiel entnehmen kann,:Warum unterstützt C# keine impliziten generischen Typen für Klassenkonstruktoren?

List<int> myInts = new List<int> {0,1,1, 
    2,3,5,8,13,21,34,55,89,144,233,377, 
    610,987,1597,2584,4181,6765}; 

//this statement is clunky 
List<string> myStrings = myInts. 
    Select<int,string>(i => i.ToString()). 
    ToList<string>(); 

//the type is inferred from the lambda expression 
//the compiler knows that it's taking an int and 
//returning a string 
List<string> myStrings = myInts. 
    Select(i => i.ToString()). 
    ToList(); 

Diese für anonyme Typen benötigt wird, wo man nicht weiß, was der Typ-Parameter sein würde (In Intellisense erscheint es als 'a), weil es vom Compiler hinzugefügt wird.

Class-Level-Typ Parameter lassen Sie sich nicht Sie dies tun:

//sample generic class 
public class GenericDemo<T> 
{ 
    public GenericDemo (T value) 
    { 
     GenericTypedProperty = value; 
    } 

    public T GenericTypedProperty {get; set;} 
} 

//why can't I do: 
int anIntValue = 4181; 
var item = new GenericDemo(anIntValue); //type inference fails 

//however I can create a wrapper like this: 
public static GenericDemo<T> Create<T> (T value) 
{ 
    return new GenericDemo<T> (value); 
} 

//then this works - type inference on the method compiles 
var item = Create(anIntValue); 

Warum nicht C# Unterstützung dieser Klasse Ebene generic Typinferenz?

+0

Warum hat diese Frage eine Abstimmung, um dagegen als Duplikat von [Warum kann der C# -Konstruktor den Typ nicht schließen?] (http://stackoverflow.com/questions/3570167) wenn diese Frage zwei Jahre jünger ist? Sicher, das ist das Duplikat? – Keith

+0

Ich denke, die andere Frage ist prägnanter, und es hat eine bessere Antwort. – Sam

+0

@Sam - Ja, Eric Lipperts Antwort auf diese Frage ist maßgebend, aber ich denke nicht, dass beide Fragen geschlossen werden sollten. – Keith

Antwort

25

Eigentlich ist Ihre Frage nicht schlecht. Ich habe in den letzten paar Jahren mit einer generischen Programmiersprache gespielt und obwohl ich nie dazu gekommen bin, sie wirklich zu entwickeln (und wahrscheinlich auch nie), habe ich viel über generische Typinferenz nachgedacht und eine meiner wichtigsten Prioritäten war immer die Konstruktion von Klassen zu erlauben, ohne den generischen Typ angeben zu müssen.

C# fehlt einfach das Regelwerk, um dies zu ermöglichen. Ich denke, die Entwickler haben nie die Notwendigkeit gesehen, dies zu berücksichtigen. Eigentlich würde der folgende Code Ihrem Vorschlag sehr nahe kommen und das Problem lösen. Alle C# benötigt ist eine zusätzliche Syntax-Unterstützung.

class Foo<T> { 
    public Foo(T x) { … } 
} 

// Notice: non-generic class overload. Possible in C#! 
class Foo { 
    public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); } 
} 

var x = Foo.ctor(42); 

Da dieser Code tatsächlich funktioniert, haben wir gezeigt, dass das Problem nicht ein von Semantik ist aber nur eine der Unterstützung fehlt. Ich denke, ich muss meinen vorherigen Beitrag zurücknehmen. ;-)

11

Warum unterstützt C# diese generische Typ-Inferenz auf Klassenebene nicht?

Weil sie im Allgemeinen mehrdeutig sind. Im Gegensatz dazu ist Typinferenz für Funktionsaufrufe trivial (wenn alle Typen in Argumenten vorkommen). Aber im Fall von Konstruktoraufrufen (verherrlichte Funktionen, um der Diskussion willen) muss der Compiler mehrere Ebenen gleichzeitig auflösen. Eine Ebene ist die Klassenebene und die andere ist die Konstruktorargumentebene. Ich glaube, das zu lösen ist algorithmisch nicht-trivial. Intuitiv würde ich sagen, dass es sogar NP-vollständig ist.

Um einen Extremfall dar, in der Auflösung nicht möglich ist, stellen Sie sich die folgende Klasse und mir sagen, was der Compiler tun soll:

class Foo<T> { 
    public Foo<U>(U x) { } 
} 

var x = new Foo(1); 
+0

Aus der Art und Weise, wie die Konrad-Frage formuliert wird, weiß ich bereits, dass der Typ "int" nicht einfach aus dem "new Foo (1)" - Beispiel abgeleitet werden kann, aber könnte mir jemand erklären warum nicht? Ich meine, wenn ich "var x = 1" sage, endet ich mit einem int. Wie unterscheidet sich das dann von diesem Beispiel? –

+0

Ich glaube nicht * Weil sie im Allgemeinen zweideutig sind * ist ein sehr guter Grund; generische Methoden sind auch mehrdeutig, wenn nicht-generische mit denselben Signaturen vorhanden sind. – Sam

+0

@Sam stimme ich völlig zu, daher meine andere (akzeptierte) Antwort. Ich glaube jedoch, dass dies der ursprüngliche Grund ist, warum sie in C# nicht existieren. Diese Frage ist wirklich alt, die Antworten werden geschrieben, bevor Stack Overflow strengere Regeln in Bezug auf Antworten erzwingt und bevor Kommentare implementiert wurden - als Konsequenz liest dieser ganze Thread mehr als eine Diskussion (was es war). Der einzige Grund, warum ich diese Antwort nicht gelöscht habe, ist, dass ansonsten der Rest der Antworten hier noch verwirrender wird –

2

Dank Konrad, das ist eine gute Antwort (1), aber nur zu erweitern darauf.

Nehmen wir an, dass C# eine explizite Konstruktorfunktion hat:

//your example 
var x = new Foo(1); 

//becomes 
var x = Foo.ctor(1); 

//your problem is valid because this would be 
var x = Foo<T>.ctor<int>(1); 
//and T can't be inferred 

Sie haben ganz recht, dass der erste Konstruktor kann nicht geschlossen werden.

Lassen Sie sich nun auf die Klasse zurück

class Foo<T> 
{ 
    //<T> can't mean anything else in this context 
    public Foo(T x) { } 
} 

//this would now throw an exception unless the 
//typeparam matches the parameter 
var x = Foo<int>.ctor(1); 

//so why wouldn't this work? 
var x = Foo.ctor(1); 

Natürlich, wenn ich Ihren Konstruktor zurück in (mit seinem alternativen Typ) füge wir einen zweideutigen Ruf haben - genau so, wie wenn eine normale Überlast-Methode konnte nicht gelöst werden.

Verwandte Themen