2013-08-08 6 views
10

Hier haben wir eine einfache Klasse herarchy, und die Verwendung von Generika mit einem type constraint von new()Allgemeintypeinschränkung neuer() und eine abstrakte Basisklasse

public abstract class Base 
{ 
} 

public class Derived : Base 
{ 
} 

public class TestClass 
{ 
    private void DoSomething<T>(T arg) where T : new() 
    { 
    } 

    public void TestMethod() 
    { 
     Derived d1 = new Derived(); 
     DoSomething(d1); // compiles 

     Base d2 = new Derived(); 
     DoSomething(d2); // compile error 
    } 
} 

Der Code in der angegebenen Zeile zu kompilieren fehlschlägt, mit ein Fehler von:

‚Base‘ ein nicht-abstrakten Typ mit einem öffentlichen parameterlosen Konstruktor, um sie als Parameter ‚T‘ in der generischen Art oder Methode zu verwenden sein muss ‚Foo.DoSomething (T)‘

Dieser Fehler ist klar und sinnvoll, aber ich hatte gehofft, dass der Compiler würde verstehen, dass alle Ableitungen von Base (die an dieser Stelle instanziiert werden könnte) einen öffentlichen parameterlosen Konstruktor haben.

Wäre das theoretisch möglich für den Compiler?

+0

Es ist diese Zeile, die mir mehr "nicht abstrakte Art" als die parameterlose Konstruktorklausel –

Antwort

8

Alas Sie ausdrücklich auf die Art geben

DoSomething<Derived>(d2); 

theoretisch nicht möglich ist, etwas zu schaffen, das

abstrakt ist
+5

Ich mag den "theoretischen" Teil. Ich habe das Gefühl, dass Jon Skeet hereinkommt, etwas Magie macht, und dann gehts, instanziiertes abstraktes Objekt. –

+0

Auf welcher .NET-Version kompiliert es, wenn d2 als abstrakte Basis deklariert ist? –

1

new Constraint (C# Reference):

die neue Einschränkung zu verwenden, kann der Typ nicht sein abstrakt.

Aufruf:

Base d2 = new Derived(); 
DoSomething(d2); 

Sie sind in der Tat zu tun:

Base d2 = new Derived(); 
DoSomething<Base>(d2); 

Da die Base abstrakt ist, Übersetzungsfehler auftritt.

Also, Sie haben ausdrücklich zu werfen:

Base d2 = new Derived(); 
DoSomething((Derived) d2); 

Wie könnte man die Compiler sicherstellen, dass jemand jemals setzte es etwas, das ist nicht abstrakt?

Die einzige Art, die ich sehe, wäre, wenn wir ein Schlüsselwort wie "must-inherit-to-non-astract" bekommen und dann public must-inherit-to-non-abstract abstract class Base erstellen. Danach kann der Compiler sicher sein, dass, wenn Sie die Basisinstanz in Ihre Methode einfügen, dies tatsächlich eine Unterklasse ist, die nicht abstrakt ist und daher instanziiert werden kann.