2017-06-11 9 views
1

Ich habe Schwierigkeiten, dieses Szenario mit Casting zu verstehen. Für Demozwecke erstellt ich diese Klassen:Upcasting abgeleitete Klasse zur Basisklasse in C#

public interface IFoo {} 
    public class Foo : IFoo 
    { 
      public string Name { get; set; } 
    } 
    public class Bar : Foo 
    { 
      public string Surname { get; set; } 
    } 

Nun, ich in meiner Main-Methode eine statische Methode erstellt, die IFoo zurückgibt:

class Program 
    { 
     static void Main() 
     { 
      IFoo iFoo = GetIFoo(); 
      Foo foo = (Foo)iFoo; 

      //the GetType ext method is executed and it returns Bar 
      if(foo is Foo) 
       Console.WriteLine($"foo is of type: {foo.GetType()}"); 

      Console.ReadLine(); 
     } 

     static IFoo GetIFoo() 
     { 
      var bar = new Bar 
      { 
       Name = "MyName", 
       Surname = "MySurname" 
      } 
      return bar; 
     } 
    } 

Die Frage ist: obwohl ich eine Bar bin zu schaffen in der GetIFoo-Methode, warum ist es, dass, wenn ich die IFoo zu Foo, foo Typ ist Bar und nicht Foo?

Antwort

2

warum ist es, dass, wenn ich die iFoo zu Foo Gießen, foo ‚s Typ Bar und nicht Foo?

Dies liegt daran, dass Casting den statischen Typ ändert. Es hat keine Auswirkungen auf den dynamischen Typ. foostatische Typ ist Foo, aber dynamische Typ ist Bar.

Jede Variable hat einen Typ an den Compiler bekannt (statischen Typ) und einen Typ der Laufzeit bekannt (dynamischen Typ). In einigen Fällen sind diese beiden Typen gleich, aber sie müssen nicht immer gleich sein.

Statischer Typ ist der deklarierte Typ der Variablen. Dynamischer Typ ist, was Sie erhalten, indem Sie GetType aufrufen, nachdem ein Objekt dieser Variablen zugewiesen wurde.

Sie haben ein Beispiel erstellt, wenn ein statischer Typ einer Variablen nicht mit dem dynamischen Typ übereinstimmt: iFoo hat den statischen Typ IFoo, aber sein dynamischer Typ ist Bar.Das ist völlig in Ordnung, denn Bar ist kompatibel mit IFoo, weil es die Schnittstelle implementiert, und auch mit Foo, weil es die Klasse erweitert.

+0

Kann der dynamische Typ Bar zur Laufzeit in Foo umgewandelt werden? – allencage

+0

Danke, ich habe die Antwort auf meinen Kommentar gefunden. Genau das wollte ich verstehen. – allencage

1

Das ist wirklich inheritance 101: Das erstellte Objekt ein Bar und Gießen wirkt, wie Sie Ansicht es, nicht das, was es wirklich ist.

Hier sehen Sie es als IFoo:

IFoo iFoo = GetIFoo(); 

Und hier absichtlich Sie es als Foo anzuzeigen. Es war kein Foo oder einer seiner Nachkommen, Sie würden eine Laufzeit von InvalidCastException bekommen.

Foo foo = (Foo)iFoo; 

A Bar Instanz kann legal mit als Bar, Foo und IFoo (und als Object aus Gründen der Vollständigkeit) gearbeitet werden. Unabhängig davon, wie Sie die Instanz anzeigen, bleibt eine Bar.

+1

Bedeutet, dass die einzige Möglichkeit, ein Foo-Objekt zu bekommen, ist, einen zu instantiieren und dann einen Konstruktor zu haben, der die notwendigen Eigenschaften von einem anderen Objekt übernimmt? – allencage

+0

@allencage Ja. Casting * ändert (konvertiert) den tatsächlichen Typ eines Objekts nicht. Sobald Sie es wie eine "Bar" instanziieren, bleibt es eine "Bar". –

1

Type.GetType gibt Ihnen den Typ der zugrunde liegenden Instanz (d. H. Den Typ, den Sie nach new angeben), unabhängig davon, um welchen Typ von Variablen es sich handelt. foo is Foo gibt true nicht nur dann, wenn die tatsächliche Instanz Foo ist, sondern für jeden Typ, der von Foo abgeleitet wird.

0

Da mit der Zeile:

Foo foo = (Foo) iFoo; 

Sie tun nicht convert: a Bar ist ein Foo und ein IFoo alle zur gleichen Zeit. Wenn Sie also in umwandeln, bemerkt der C# -Dolmetscher, dass iFoo ein Bar ist und lässt das Objekt unberührt. Der Punkt ist, dass der Compiler von nun an annehmen wird, dass foo tatsächlich ein Foo Objekt ist, aber es kann von jeder Klasse sein, die die Foo Klasse erweitert.

wir machen es klar, mit dem folgenden Beispiel:

interface IDriveable {} // IFoo 
class Car : IDriveable { // Foo 
    string Name {get; set; } 
} 
class Volkswagen : Car { // Bar 
    bool CorrectPolution { get; set; } 
} 

Nun, wenn Sie ein Volkswagen konstruieren, zehn offensichtlich, dass ein Car ist und ein IDriveable. Aber mit den Worten: Car car = (Car) volkswagen;. Sie tun nicht ändern Sie den Volkswagen, Sie nur jetzt lassen Sie den Compiler wissen, dass car ein Car Objekt ist.

1

Weil GetType() Rückgabetyp des Objekts. Wenn Sie die abgeleitete Klasse explizit in die Basisklasse umwandeln, haben Sie keine neue Instanz erstellt, sondern nur eine neue typisierte Referenz für das vorhandene Objekt. Sie können es mit dem Code siehe unten:

IFoo iFoo = GetIFoo(); 
Foo foo = (Foo)iFoo; 
Console.WriteLine(ifoo.Equals(foo)); 
1

Sie zwischen dem Laufzeittyp eines Objekts und seiner Kompilierung-Typ verwechselt werden.

IFoo iFoo = GetIFoo(); 

In der obigen Zeile iFoo ‚s Laufzeit-Typ ist immer noch Bar. Dies ist der wahre Typ des Objekts. Aber wenn Sie auf das Bar Objekt über eine Referenz vom Typ IFoo zugreifen, dann weiß der Compiler nur, dass der Typ IFoo ist, daher der Kompilierzeittyp des Objekts genannt, auf das durch Referenz iFoo verwiesen wird. Beachten Sie, dass der Compiler diese Typinformation verloren hat, wenn die return bar-Anweisung in GetIFoo ausgeführt wurde.

Foo foo = (Foo)iFoo; 

Weiter unten, können Sie es werfen, was auch immer Art wollen Sie in der Hierarchie der Bar, etwas oberhalb und einschließlich Bar erfolgreich sein wird, und die Kompilierung Typ wird auf der Grundlage, was Sie eingeben gegossen es. Aber wieder der Laufzeittyp wird immer noch derselbe bleiben, d. H. Bar

+0

Danke für die Antwort. Dies macht die Dinge klarer. Gibt es eine andere Möglichkeit, einen Foo zur Laufzeit mit diesem Ansatz zu erstellen? – allencage

+0

@allencage Wenn Sie Ihre Methode 'GetIFoo' wie folgt ändern' static IFoo GetIFoo() {var foo = new Foo {Name = "MeinName"}; Rückkehr foo; } 'dann wäre Ihr Laufzeittyp und der Kompilierzeittyp beide" Foo ". – Vikhram

Verwandte Themen