2010-03-25 10 views
7

Ich erweitere die vorhandene .NET-Framework-Klasse, indem ich es ableite. Wie konvertiere ich ein Objekt vom Basistyp in den abgeleiteten Typ?Convert/Cast-Basistyp in abgeleiteten Typ

public class Results { //Framework methods } 

public class MyResults : Results { //Nothing here } 

//I call the framework method 

public static MyResults GetResults() 
{ 
    Results results = new Results(); 
    //Results results = new MyResults(); //tried this as well. 

    results = CallFrameworkMethod(); 

    return (MyResults)results; //Throws runtime exception 
} 

Ich verstehe, dass dies geschieht, wie ich versuche, einen Basistyp zu einem abgeleiteten Typ zu werfen und wenn abgeleiteten Typ zusätzliche Eigenschaften hat, dann wird der Speicher nicht zugeordnet. Wenn ich die zusätzlichen Eigenschaften hinzufüge, ist es mir egal, ob sie auf Null initialisiert werden.

Wie mache ich das, ohne eine manuelle Kopie zu machen?

+1

Anstatt den Typ zu erweitern, können Sie einfach eine Erweiterungsmethode erstellen? –

+0

Das ist eine gute Idee. Mit Extension-Methoden kann ich neue Methoden anhängen. Ich kann dem Typ keine zusätzlichen Eigenschaften/Variablen hinzufügen. – Nick

+0

Das scheint eine Menge Arbeit zu sein, um das Schreiben eines einfachen Kopierkonstruktors zu vermeiden. Ich weiß in vielen Fällen, dass das nicht möglich ist, aber in diesem Fall scheint es eine mögliche Lösung zu sein. – overslacked

Antwort

11

Sie können nicht . Wenn sich results nicht auf MyResults bezieht (z. B. wenn CallFrameworkMethod eine Basis Results Instanz zurückgibt), wird das Casting es nicht machen: Sie müssen ein neues MyResults erstellen, basierend auf dem vorhandenen Nicht-MyResults. Bei der Umwandlung geht es darum, den Kompilierungszeittyp der Referenz zu ändern, nicht den konkreten Typ des referenzierten Objekts zu ändern.

Sie Tools wie Reflexion oder AutoMapper können mit der Initialisierung des neuen MyResults Objekts helfen - aber ein neues MyResults Objekt muss es sein, weil Sie nicht einer Basis Results Objekt zu einem MyResults Objekt berichten.

+0

Hat das mit Varianz/Kovarianz zu tun? Ich bin auf .NET 4.0 und ich weiß, dass sie etwas für Varianz/Kovarianz gemacht haben. Irgendeine Idee? – Nick

+0

Nein, C# 4.0-Varianz hat damit zu tun, wenn Sie base/derived types als Typparameter für generische Interfaces oder Delegates verwenden; und Sie haben hier keine allgemeinen Schnittstellen oder Delegaten. Ihr Problem ist fundamentaler: Es geht um den konkreten Typ des Objekts. Ein Ergebnisobjekt ist einfach * keine * Instanz des MyResults-Typs. Wenn CallFrameworkMethod ein (tatsächliches) Ergebnis zurückgibt, können Verweise auf dieses Objekt * nicht in MyResults umgewandelt werden, da das Objekt * kein MyResults ist. Die einzige Möglichkeit ist, CallFrameworkMethod zu ändern, um MyResults zurückzugeben oder ein neues MyResults zu erstellen. – itowlson

+0

Varianz hilft dir hier nicht –

1

Wie wäre:

... 
MyResults results = new MyResults(); 
... 

Und Sie vielleicht brauchen auch eine Constructor in Ihrer MyResults Klasse zu erstellen:

public class MyResults : Results 
{ 
    public MyResults() : base() {} 
} 

Was genau bedeutet "nichts hier"?

EDIT

results = (CallFrameworkMethod() as MyResults); 

Es die Ausnahme werfen tut, aber wenn es wäre für Sie nützlich sein - es hängt davon ab, was Sie weiter tun möchte ...

+0

"nichts hier" wie im wahrsten Sinne des Wortes nichts. Vorerst habe ich vom Basistyp geerbt mit der Absicht, in der Zukunft neue Eigenschaften hinzuzufügen – Nick

+0

ich sehe. Ich habe meine Antwort bearbeitet - bitte überprüfe die neue Lösung. – Gacek

+0

@Gacek - Die Verwendung des as-Schlüsselworts löst keine Ausnahme aus, aber das MyResult-Objekt ist null, obwohl CallFrameworkMethod ein nicht null-Objekt zurückgibt. – Nick

0
Results results = new MyResults(); 
    ... 

return (MyResults)results; 

sollte funktionieren. Wenn nicht, dann ist das Problem irgendwo anders.

+1

Nein, weil er es dann mit dem Rückgabewert von CallFrameworkMethod überschreibt - was vermutlich etwas anderes als ein MyResults zurückgibt, oder die Besetzung würde gelingen. – itowlson

+0

CallFrameworkMethod() gibt das Objekt vom Typ Results zurück – Nick

+0

Er erstellt eine Instanz der MyResult-Klasse und ruft dann die CallFrameworkMethod-Methode auf, die dem Ergebnisobjekt eine andere Instanz zuweist, die nicht gegossen werden kann. – Machta

1

Nein, Sie können nicht vermeiden, den Inhalt in eine Instanz des abgeleiteten Typs zu kopieren. Nun, wenn Sie CallFrameworkMethod als generische Methode und MyResults als Konstruktor mit null Argumenten ändern können, kann CallFrameworkMethod eine neue Instanz Ihres abgeleiteten Typs direkt erstellen und dann nur die Member des übergeordneten Typs verwenden.

Aber wahrscheinlich müssen Sie am Ende auf ein neues Objekt kopieren. Denken Sie daran, dass dieser Kopiercode sicherlich in einer anderen Methode wiederverwendet werden kann, Sie müssen ihn nicht überall neu schreiben, wo Sie ihn brauchen.

+0

Wie würde der Kopierkonstruktor aussehen? Kannst du mir ein paar Hinweise geben? – Nick

+0

C# hat keine "Kopierkonstruktoren". Sie können jedoch eine wiederverwendbare Methode schreiben, die die Basisklasse akzeptiert und eine Instanz der abgeleiteten Klasse mit allen kopierten Basisklassenelementen zurückgibt. Oder fragen Sie nach der generischen Idee? –

1

Wie bereits in früheren Antworten erwähnt, müssen Sie eine neue Instanz von MyResults instantiieren und dann die Eigenschaften aus Ihrem Results-Objekt kopieren. Sie haben gefragt, was ein "Kopierkonstruktor" ist - es ist nur ein Konstruktor, der ein Objekt übernimmt und es verwendet, um das zu konstruierende Objekt zu füllen.Zum Beispiel:

public class Results 
    { 
     public string SampleProperty1 { get; set; } 
     public string SampleProperty2 { get; set; } 
    } 

    public class MyResults : Results 
    { 
     public MyResults(Results results) 
     { 
      SampleProperty1 = results.SampleProperty1; 
      SampleProperty2 = results.SampleProperty2; 
     } 
    } 

Eine Kopie Konstruktor ist in der Regel bequeme, lesbar und wiederverwendbar als Code wie folgt verwendet:

MyResults myResults = new MyResults 
{ 
    SampleProperty1 = results.SampleProperty1, 
    SampleProperty2 = results.SampleProperty2 
}; 

Wenn es gibt viele Eigenschaften und/oder Sie machen viele Änderungen die Klasse, die Sie verwenden könnten, um eine Reflektion zu verwenden (zB C# Using Reflection to copy base class properties) oder ein Werkzeug wie AutoMapper (http://automapper.codeplex.com), um die Eigenschaften zu kopieren. Aber oft kann das Overkill sein.

Verwandte Themen