2016-08-30 2 views
6

Was ist eine allgemeine Regel zu prüfen, ob IEnumerable<T1> kovariant zu IEnumerable<T2>?Wie überprüfe ich, ob `IEnumerable <T1>` kovariant zu `IEnumerable <T2>` `?


1.

Object Obj = "Test string"; 
IEnumerable<Object> Objs = new String[100]; 

Works weil IEnumerable<out T> covariant und String erbt Object:

ich einige Experimente gemacht haben.

2.

interface MyInterface{} 
struct MyStruct:MyInterface{} 
..... 
Object V = new MyStruct(); 
Console.WriteLine(new MyStruct() is Object); // Output: True. 
IEnumerable<Object> Vs = new MyStruct[100]; // Compilation error here 

MyStruct ist eigentlich ein Object, aber es funktioniert nicht, weil Object Referenztyp ist und MyStruct ist Werttyp. OK, ich sehe hier eine Logik.

3.

Console.WriteLine(new MyStruct() is ValueType); // Output: "True" 
ValueType V2 = new MyStruct(); 
IEnumerable<ValueType> Vs2 = new MyStruct[100]; // Compilation error here 

Sollte arbeiten, weil IEnumerable<out T> covariant und MyStruct IS ValueType, aber nicht funktioniert ... OK, vielleicht MyStruct nicht wirklich inheritst ValueType ....

4.

Auch so: "Kann MyStruct nicht in MyInterface konvertieren". Ja wirklich?? Du hast es nur eine Zeile vor ...


Ich habe versucht, gemeinsame Regel zu formulieren:

public static bool IsCovariantIEnumerable(Type T1, Type T2 ){   
    return (T2.IsAssignableFrom(T1)) && !T2.IsValueType; // Is this correct?? 
} 

So sind Fragen, wie eigentlich zu bestimmen, ob IEnumerable<T1> covariant zu IEnumerable<T2> ? Ist meine IsCovariantIEnumerable(...) Funktion korrekt? Wenn ja, gibt es einen einfacheren Weg, es zu überprüfen? Wenn nicht, wie repariere ich es?

Siehe auch diese Artikel: 1, 2.

+0

Werttypen unterstützen Kovarianz einfach nicht; Es sollte nicht überraschend sein, da Werttypen * Vererbung * überhaupt nicht unterstützen. Wenn Sie einen Werttyp als Schnittstelle und/oder "Objekt" verwenden müssen, müssen Sie ihn z. 'array.Cast '. Es ist nicht klar, welchen Teil davon du nicht verstehst, vorausgesetzt, dass die Fragen, die du verlinkt hast, genau diese Frage beantworten :) – Luaan

+0

@Luaan, ich möchte nur die vollständige Regel haben, um zu überprüfen, ob IEnumerable 'kovariant zu' IEnumerable ist '. Ich bin mir immer noch nicht sicher, ob meine Funktion 'IsCovariantIEnumerable()' korrekt ist. – Astronavigator

+1

In Bezug auf unterstützende Schnittstellen kann ['IsAssignableFrom'] (https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom (v = vs.110) .aspx) besser sein als' IsSubclassOf ' – grek40

Antwort

5

In Ihrem speziellen Fall ist es nicht funktioniert, weil Werttypen Kovarianz nicht unterstützen.

Aber für die Frage, wie zu bestimmen, ob eine IEnumerable<T2> Co-Variante zu IEnumerable<T1> ist:

Verfahren Type.IsAssignableFrom() Sie sagt, wenn eine Instanz eines bestimmten Typs assignalbe auf eine Variable dieses Typs ist. So können Sie Ihre Methode so implementieren:

public static bool IsCovariantIEnumerable(Type T1, Type T2) 
{ 
    Type enumerable1 = typeof(IEnumerable<>).MakeGenericType(T1); 
    Type enumerable2 = typeof(IEnumerable<>).MakeGenericType(T2); 
    return enumerable1.IsAssignableFrom(enumerable2); 
} 

Verbrauch:

if (IsCovariantIEnumerable(typeof(object), typeof(string)) 
    Console.WriteLine("IEnumerable<string> can be assigned to IEnumerable<object>"); 

Aber IsCovariantIEnumerable(typeof(object), typeof(MyStruct)) wird return false für die oben genannten Grund.


Der Vollständigkeit halber: Natürlich brauchen Sie nicht eine zusätzliche Methode, wie Sie leicht typeof(IEnumerable<object>).IsAssignableFrom(typeof(IEnumerable<string>) tun können.

+0

Das Überprüfen des 'IEnumerable <...>' -Typs auf Zuordnungsfähigkeit ist definitiv einfacher als das Erraten des Elementtypverhaltens. Saubere Lösung, an die ich nicht gedacht habe. – grek40

+0

@ grek40 Sie haben recht, ich habe über die Methodenimplementierung von OP nachgedacht und dabei den direkten Aufruf von 'IsAssignableFrom' vergessen. Es wurde der Vollständigkeit hinzugefügt. –

+0

Ich sehe, dass Ihre 'IsCovariantIEnumerable' gut funktioniert. Aber immer noch Frage ist: "Ist meine' IsCovariantIEnumerable' auch korrekt oder nicht? " Gibt es Beispiele, in denen Ihre Funktion funktioniert, aber meine nicht? – Astronavigator

2

Werttypen unterstützen keine Kovarianz, da sie ihre interne Darstellung ändern würde [1].

Wenn Sie seltsame Fälle vermeiden wollen, würde ich stattdessen mit IsAssignableFrom empfehlen:

public static bool IsCovariantIEnumerable(Type T1, Type T2) => T1.IsAssignableFrom(T2);

Verwandte Themen