2009-01-07 3 views
13

Nicht ganz sicher, wie man die Frage formuliert, weil es ein "warum funktioniert das nicht?" Art der Abfrage.Generische Constraints und Interface-Implementierung/Vererbung

Ich habe mein besonderes Problem reduziert bis zu diesem Code:

public interface IFoo 
{ 
} 

public class Foo : IFoo 
{ 
} 

public class Bar<T> where T : IFoo 
{ 
    public Bar(T t) 
    { 
    } 

    public Bar() 
     : this(new Foo()) // cannot convert from 'Foo' to 'T' 
    { 
    } 
} 

Nun wird der generische Typ T in der Bar<T> Klasse muss IFoo implementieren. Warum gibt mir der Compiler den Fehler im Kommentar? Sicherlich ist eine Instanz von Foo ein IFoo und kann daher als Vertreter des generischen Typs T weitergegeben werden?

Ist dies eine Compiler-Einschränkung oder fehle ich etwas?

Antwort

13

Sie könnten auch einen Fiz, die IFoo implementiert, die nicht zu Foo auf andere Weise verbunden ist:

public interface IFoo 
{ 
} 

public class Foo : IFoo 
{ 
} 

public class Fiz : IFoo 
{ 
} 

Foo foo = new Foo(); 
Fiz fiz = foo; // Not gonna compile. 

Was Sie wollen, ist wahrscheinlich eher wie:

public class Bar<T> where T : IFoo, new() 
{ 
    public Bar(T t) 
    { 
    } 

    public Bar() 
     : this(new T()) 
    { 
    } 
} 

So können Sie

Bar<Foo> barFoo = new Bar<Foo>(); 
Bar<Fiz> barFiz = new Bar<Fiz>(); 
+0

Das ist süß, weil ich nicht wusste, dass du das neue T() Ding, du hast gerade mein Leben in einem Projekt speichern können, an dem ich arbeite. Prost :) –

2

Wenn Sie eine Klasse Baz und dann den generischen Typ Bar baz = new Bar() erstellen, wäre new Foo(), wie von Ihrer Konstruktorüberladung definiert, nicht vom Typ T, in diesem Fall Baz.

+0

+1 Dank yshuditelu. Ich gebe Andrew die akzeptierte Antwort, da sein Code mit den Codebeispielen etwas umfangreicher ist (und Sie waren nur 8 Sekunden voneinander entfernt). :) –

+0

Einverstanden (und danke). –

0

Es ist, weil, wenn Sie eine Klasse erstellen:

Und dann instanziiert Bar<T> wie folgt aus:

var bar = new Bar<Fred>(); 

Dann ist es die Zwänge der Klasse als Foo verletzt ist kein Fred, die die aktuelle T ist.

Sie können ihn zwingen, indem man den gegossenen Sequenz (T)(IFoo)new Foo() im Konstruktor zu kompilieren, aber Sie werden eine InvalidCastException zur Laufzeit, wenn sich der tatsächliche Typ T nicht aus Foo zuweisbar ist.