2017-06-18 2 views
3

Sagen wir, wir haben diese Typen:C# Typ Generisches Kind Übergeordnetes Casting

class A {} 
class B : A {} 

class X<T> {} 

Warum wir dies nicht tun können?

X<A> var = new X<B>(); 

Gibt es eine Problemumgehung?

[Bearbeiten] Ich versuchte Kovarianz zu verwenden, aber es scheiterte, weil ich eine Struktur, die in X zugreifen möchten, die vom Typ T und C# erlaubt es ist nicht Typ T in der Schnittstelle:

interface IX<out T> { 
    T sth {set; get;} 
} 

class X<T>: IX<T> { 
    T sth { set; get; } 
} 

[Edit 2] ich das auch versucht, aber es ist fehlgeschlagen:

class X<T> where T : A 
{ 
    public T sth { set; get; } 

    public static implicit operator X<T>(X<B> v) 
    { 
     return new X<T> 
     { 
      sth = v.sth, 
     }; 
    } 
} 

es ist seltsam, dass C# nicht für ‚etw‘ auf das Gießen nicht gestattet.

+1

In __ [Edit 2] __, wenn Sie sagen, 'neue X {...}', denken Sie daran, dass 'T' mit jedem konkreten Typ ersetzt werden kann, wenn Das läuft. Was ist, wenn zum Beispiel "T" vom Typ "Klasse Evil: A" ist? Dann weisen Sie 'v.sth' mit dem Typ' B' einer Eigenschaft vom Typ 'Evil' zu. Aber sie haben keine kompatiblen Typen. Die einzige "Beziehung" zwischen ihnen ("B" und "Böse") ist, dass beide von "A" abstammen. Ein 'B' ist also kein' Evil', also wäre die Zuordnung illegal. Da die Zuweisung für einige Ersetzungen für "T" unzulässig ist, ist die Zuweisung im Allgemeinen illegal. –

+0

@JeppeStigNielsen Sie haben recht über [Edit 2] – HamedH

Antwort

1

Das Problem ist, dass Klassen nicht Kovarianz und Kontra nicht unterstützt, Schnittstellen nur:

class A { } 
class B : A { } 

class X<T> : P<T> { } 

interface P<out T> 
{ 
} 

... 

P<A> var = new X<B>(); 

Covariance and Contravariance FAQ

+1

Es ist erwähnenswert, dass Klassen nicht Covariance und Kontravarianz unterstützen, das ist der Grund, warum wir eine Schnittstelle verwenden. – Deadzone

+0

Ich kann Kovarianz nicht verwenden, da ich eine Eigenschaft vom Typ T in A habe. – HamedH

1

Sie benötigen Kovarianz (T mit dem Wort out den Typ Parameter markieren):

interface IX<out T> {} 

Dies ist nur mit Schnittstellentypen (und Delegattypen) zulässig. Und der Typ B muss ein Referenztyp sein (class wie hier ist OK).

Dann ist dieses fein:

IX<B> ixb = ...; 
IX<A> ok = new IX<B>(); 
+0

Ich kann Kovarianz nicht verwenden, da ich eine Eigenschaft vom Typ T in A habe. – HamedH

+1

Ich bin mir nicht sicher, ob ich dir folgen kann. Wenn eine Eigenschaft "gesetzt" werden kann, ist "out" nicht erlaubt, da dies die Dinge zerstören würde. Wenn Sie zum Beispiel eine IList haben und ___if___ 'IList <>' auch dann kovariant sein könnte, wenn sie einen Indexer mit einem 'set'-Accessor besitzt, dann könnten Sie diese Liste als' IList 'behandeln, nennen Sie sie 'animalList' '. Dann würde 'animalList [0] = new Elephant();' einen Elefanten in eine Liste von Katzen einfügen. Können Sie jetzt sehen, warum eine Eigenschaft vom Typ 'T', die einen 'set'-Zugriffsmechanismus hat, es unmöglich macht, die Kovarianz in' T' anzufordern. (Vergleichen Sie 'IReadOnlyList ', die nur 'get', no' set' haben.) –