2015-12-11 6 views
9

In dem folgenden Beispielcode Geben, warum der Ruf nach einem Genric Typ ArrayMethod nicht fehlschlagen, wenn ich die class Einschränkung nicht verstehenein Array

public interface IFoo { } 
public interface IBar : IFoo { } 

public class Test 
{ 
    public void ClassConstraintTest<T>() where T : class, IFoo 
    { 
     T[] variable = new T[0]; 
     ArrayMethod(variable); 
    } 

    public void GenericTest<T>() where T : IFoo 
    { 
     T[] variable = new T[0]; 
     ArrayMethod(variable); // Compilation error: Can't convert T[] to IFoo[] 
    } 

    public void InheritanceTest() 
    { 
     IBar[] variable = new IBar[0]; 
     ArrayMethod(variable); 
    } 

    public void ArrayMethod(IFoo[] args) { } 
} 

Antwort

9

Es ist, weil array covariance, dh die Tatsache, dass MySubtype[] ist ein Subtyp von MyType[], funktioniert nur für Referenztypen. Die class-Einschränkung stellt sicher, dass T ein Referenztyp ist.

(Man beachte, dass im Nachhinein Matrixkovarianz considered to be a bad idea ist versuchen, es zu vermeiden, wenn Sie können, zum Beispiel, indem sie ArrayMethod Generika oder durch IEnumerable<IFoo> stattdessen verwenden..)

+0

Ein gutes Typsystem sollte einen kovarianten Typ haben, der als ein Array verwendet werden kann, dessen Elemente innerhalb des Arrays gelesen, vertauscht oder kopiert werden können. Array-Typen in .NET und Java können als solche Typen sicher in kovarianter Weise verwendet werden und können sicher in nicht-kovarianter Weise als frei beschreibbare Sammlungen verwendet werden. Vielleicht wäre es besser gewesen, mehrere Arten von Verweisen auf Arrays mit unterschiedlichen beworbenen Fähigkeiten zu haben, aber IMHO diejenigen, die einfach sagen, dass kovariante Arrays ein "Fehler" waren, haben die Kosten der Alternativen nicht wirklich herausgefunden. – supercat

5

Kurz gesagt: Matrixkovarianz funktioniert nur, wenn Beide Arrays sind von einem Referenztyp (class).

Um dies zu verstehen, müssen Sie das Speicherlayout verschiedener Arten von Arrays verstehen. In C# haben wir Wert Arrays (int[], float[], DateTime[], alle benutzerdefinierten struct[]), wobei jedes Ding sequentiell innerhalb des Arrays gespeichert ist, und die Referenzarrays (object[], string[], alle benutzerdefinierten class[], interface[] oder delegate[]) wobei Referenzen werden sequentiell innerhalb des Arrays gespeichert und die Objekte werden außerhalb des Arrays gespeichert, wo immer sie in den Speicher passen.

Wenn Sie fordern, dass die Methode die Arbeit an jedem T (ohne die : class constraint) ermöglichen es, für eine dieser beiden Arten von Arrays, aber der Compiler weiß für eine Tatsache, dass jede int[] (oder jeder andere Wert Array) nicht wird irgendwie magisch zu einem gültigen IFoo[] (oder einem anderen Referenzarray) und verbietet die Konvertierung. Das passiert selbst dann, wenn Ihre Struktur IFoo aus einem anderen Grund als IFoo[] ein Referenz-Array implementiert und ein T[] ein Werte-Array ist.

Wenn Sie jedoch angeben, dass T ist ein Referenztyp (das heißt die class Erklärung) ist es nun möglich, dass die T[] ein gültiges IFoo[] ist, weil sie beide Referenz Arrays sind. So erlaubt der Compiler dem Code die Verwendung der Array-Kovarianzregeln (in der Sie angeben können, dass T[]IFoo[] erforderlich ist, da T ein Untertyp von IFoo ist).

Verwandte Themen