2016-07-25 7 views
1

C# 6.0 in Kürze durch Joseph Albahari und Ben Albahari (O'Reilly).Typ Covariance Laufzeitfehler

Copyright 2016 Joseph Albahari und Ben Albahari, 978-1-491-92706-9. aus historischen Gründen, Array-Typen Kovarianz unterstützen

Arrays:

Staaten, auf den Seiten 123-124, in Bezug Kovarianz geben. Diese bedeutet, dass B [] in A [] umgewandelt werden kann, wenn B-Unterklassen A (und beide sind Referenztypen).

Zum Beispiel:

Bear[] bears = new Bear[3]; 
Animal[] animals = bears; // OK 

Der Nachteil dieser Wiederverwertbarkeit ist, dass Element Zuordnungen können zur Laufzeit fehlschlagen:

animals[0] = new Camel(); // Runtime error 

Was ist der Grund für diese Fehler? Wenn Sie einer Instanz von Animal eine Instanz von Bear zuweisen, wird ein Laufzeitfehler ausgelöst. Ich verstehe nicht, warum es so sein sollte (indem ich eine solche Aufgabe zulasse, muss der Compiler die Verantwortung dafür übernehmen, dass "alles in Ordnung ist, was ein Tier tun kann." Da Bear ein Tier ist, ist dies der Fall . haupt keine Probleme

ich habe mein eigenes Szenario das oben zu testen.

public class X 
{ 
    public int Num { get; set; } 

    public void Method_1() 
    { 
     Console.WriteLine("X"); 
    } 

    public virtual void Method_2() 
    { 
     Console.WriteLine(Num); 
    } 
} 

public class Y : X 
{ 
    public Y() 
    { 
     Num = 1000; 
    } 
} 

X[] arrayX = new X[] { new X { Num = 1000 }, new X { Num = 999 }, new X { Num = 51762 } }; 
Y[] arrayY = new Y[] { new Y { Num = 5 }, new Y { Num = 6 }, new Y { Num = 7 } }; 

X x = new X { Num = 1000 }; 
Y y = new Y { Num = 50 }; 

x = y; 

arrayX = arrayY; 

arrayX[2] = new Y { Num = 1 }; 

// will print 5,6,1 - no runtime errors faced 
foreach (var e in arrayX) 
    Console.WriteLine(e.Num); 

ich das snippet oben ahmt Beispiel ist das Buch glauben - aber mit meinem Schnipsel, es gibt keine Laufzeitfehler

Was fehlt mir? Wie soll animals[0] = new Camel(); einen Laufzeitfehler geworfen werden, wie das Buch sagt?

+1

Während die "Tiere" -Array wie eine Reihe von Tieren aussieht, ist es eigentlich eine Reihe von Bären. Sie können kein Kamel zu einer Reihe von Bären hinzufügen (eindeutig würden die Bären das Kamel essen). Dein Beispiel hat Tier (X) und Bär (Y), aber es fehlt eine zweite Kindklasse wie Kamel. – juharr

Antwort

4

Was ist der Grund für einen solchen Fehler?

Weil es versucht, mit einem Laufzeittyp Bear[] ein Camel in ein Array zu speichern. Ein Array vom Typ Bear[] kann nur Referenzen auf Instanzen von Bear oder Unterklassen speichern. Der Kompilierungszeittyp von Animal[] sagt nur, dass es könnte in Lage sein, eine Camel Referenz zu speichern, und dass jede Referenz, die Sie erhalten aus des Arrays wird definitiv eine Animal Instanz oder Unterklasse sein.

Ihr Beispiel ist anders. Wenn wir alle Eigenschaften etc Streifen aus (die nicht relevant sind) Sie haben:

X[] arrayX = new Y[3]; 
arrayX[2] = new Y(); 

ist das in Ordnung - das ist eine Referenz auf ein Y Objekt in einem Array mit einer Ausführungszeit Art der Y[] speichern. Kein Problem.

Um das gleiche Problem wie das Buch zeigen Sie eine dritte Klasse bräuchten:

class Z : X {} 

X[] arrayX = new Z[3]; 
arrayX[2] = new Y(); // Bang - can't store a Y reference in a Z[] 
+0

@Veverke: Ich bin mir nicht sicher, was du meinst - aber ich schaue dir jetzt dein komplizierteres Beispiel an. –

+0

Hallo Jon, meine Frage bezieht sich auf die Aussage des Buches 'animals [0] = new Camel(); // Laufzeitfehler – Veverke

+3

@ Veverke Das ist, was Jon antwortete. – Servy

1

Ihr Beispiel mit X und Y ist ganz anders als die von Buch. Wenn Sie die aus dem Buch nachahmen möchten, erstellen Sie die abstrakte Basisklasse X und leiten Sie daraus Y und Z ab. Dann spiele damit herum. Die aus Buch bedeutet, dass:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Bear[] bears = new Bear[3]; 
     Animal[] animals = bears; 
     animals[0] = new Camel(); //will throw on runtime 
    } 
} 

public abstract class Animal { } 

public class Camel : Animal { } 

public class Bear : Animal { } 

Wie Jon bereits erwähnt, Laufzeittyp von animalsBear[] sein wird, die einfach keine Instanz Camel speichern kann. Auch beachten Sie bitte, das ist ein möglicher Fehler für covariant Array-Konvertierung, aber werde nicht für andere Sammlungen geschehen wie List:

 List<Bear> bearsList = new List<Bear>(); 
     List<Animal> animalsList = bearsList; //won't compile because of this error 
     animalsList[0] = new Camel(); 
1

In der folgenden Zeile:

Animal[] animals = bears; 

Sie sind nur versteckt Ihre Bear[] in eine Animal[].

Beachten Sie, dass ich sage versteckt, weil Sie nicht tatsächlich ein neues Array erstellen.

Sowohl bearsanimals und auf die gleiche Bear[], der einzige Unterschied besteht darin, dass diese Referenz als animalsAnimal[] versteckt.


Der Compiler weiß das nicht.

Für den Compiler, wenn Sie einen Dolphin oder ein Lion auf animals speichern möchten, wird es Sie tun lassen, so, da alle diese Elemente Animal Typ sind.


Die Laufzeit würde jedoch beschweren.

Da animals eine Bear[] verbirgt, ist das Hinzufügen einer Camel nicht zulässig.

Obwohl Bear und Camel beide von Animal erben, sind sie zwei verschiedene Arten.

0

Für diesen Code:

Animal[] bears = new Bear[3]; 

Wenn Sie ReSharper in Ihrem VS installiert ist, gibt es die gleiche Warnung aus:

Co-Variante Array Umwandlung von Bear [] zu Tier [] können Ursache Laufzeit Ausnahme bei Schreibvorgang.

Wenn Sie Generisches wie IList verwenden:

IList<Animal> bears = new List<Bear>(); 
bears.Add(new Camel()); 

die erste Zeile wird nicht zulassen, kompilieren, was sicherer ist, verhindert, dass es möglich Laufzeitausnahme.