2009-02-18 7 views
5

Ich habe eine Schnittstelle und zwei Klassen, die die Schnittstelle implementiert. Die Klassen haben generische Typen. Ich möchte von einer Instanz einer Klasse zur anderen klonen.C# Generic Copy Konstruktor

interface IFoo 
{ 
    // stuff 
} 

class Foo<T> : IFoo 
{ 
    // foo stuff 
    // ifoo implementation 
} 

class Bar<T> : IFoo 
{ 
    // bar stuff 
    // ifoo implementation 
} 

Ich habe ein Foo und möchte eine Bar. Bar hat einen Kopierkonstruktor, der einen Parameter von IFoo verwendet. Ich habe eine Erweiterungsmethode den Klon zu implementieren:

public static Bar<T> Clone<T>(this IFoo foo) 
{ 
    return new Bar<T>(foo); 
} 

Aufruf der Methode erfordert die Art:

someFoo.Clone<T> ... 

Gibt es eine Möglichkeit, die Art zu verzichten erklärt beim Aufruf der Methode durch die Erweiterungsmethode Modifizieren oder auf andere Weise, damit die Instanz einfach übergeben werden kann, ohne sich um den zugrunde liegenden Typ zu kümmern?

aktualisieren Hier ist, wie diese besser genutzt wird, um die Situation zu erläutern.

In einer Methode ich eine Sammlung iterieren und eine Aufzählung von IFoo zurückgeben. In der Methode betrachte ich ein Attribut der Quellsammlung und bestimme den Typ des Foo.

IFoo foo = null; 

string type = element.Attribute("Type").Value; 
switch (type) 
{ 
    case "int": 
     foo = new Foo<int>(); 
     break; 

    case "string": 
     foo = new Foo<string>(); 
     break; 

    // etc 
} 
// other stuff 

yield return foo; 

Die aufrufende Methode hat eine Liste. Später wähle ich einzelne Gegenstände aus dieser Liste aus, an denen ich statt eines Foo eine Bar hätte. Bei der Auswahl aus der Liste sind die Instanzen vom Typ IFoo, da sie nur die Erweiterungsmethoden für "dieses IFoo foo" sehen. Ich möchte den IFoo nicht zu einem Foo umwandeln, das würde erfordern, den Typ von T neu zu deklarieren. Ich möchte nur, dass Foo Bar sagt, was es ist. Ist das möglich?

+0

Vielleicht vermisse ich etwas, aber wenn yo Deine Extension-Funktion nehme einen IFoo, wie soll er ihn in einen Bar "klonen", wenn er vom Typ Foo ist? –

+0

Alles, was mir wichtig ist, sind die Werte in den IFoo-Eigenschaften, die von einem Foo in einen Balken kopiert werden. – blu

Antwort

0

Wenn es für Ihr Szenario funktioniert, könnten Sie eine IFoo<T> haben. Auch wenn es Ihnen nichts ausmacht, spezifische Erweiterungsmethoden zu haben, können Sie einfach eine Foo<T> erhalten. Sie müssen wirklich etwas übergeben, das auf das T verweist, damit der Compiler den entsprechenden Typ ableiten kann.

0

Wenn Sie die vollständige Kontrolle über Ihre tiefe Kopie Klon benötigen, ist dieses Muster sehr gut:

public class FooBase 
{ 
    private int x; 

    public FooBase() { /* standard contructor */ } 

    protected FooBase(FooBase clone) 
    { 
     this.x = clone.x; 
    } 

    public FooBase Clone() { return new FooBase(this); } 
} 

public class Foo : FooBase 
{ 
    private int y; 

    public Foo() { /* standard contructor */ } 

    protected Foo(Foo clone) : base(clone) 
    { 
     this.y = clone.y; 
    } 

    public Foo Clone() { return new Foo(this); } 
} 

definieren geschützt contructor für das Klonen - so abgeleiteten Klassen kann Werte in der Basisklasse klonen. Dieses Muster muss von Hand geschrieben werden (oder mit Hilfe eines guten T4-Templates erzeugt werden), ist aber sehr gut für das tiefe Klonen geeignet.

Update: Ich denke, ich habe die Frage missverstanden und bereits das Klonen implementiert. Freddy hat recht - der Compiler muss wissen, welchen Typ er ermitteln soll und es kann nicht vom Typ IFoo. Es kann es tun in (dieses Foo < T> foo) obwohl.

0

Versuchen Sie, die Methode als solche

public static Bar<T> Clone<T>(this Foo<T> foo) 
{ 
    return new Bar<T>(foo); 
} 

Auf diese Weise definieren, würde der Parameter einen generischen Typ und der Compiler würde von der Art, die eine Quelle haben für Folgern.

2

So haben Sie alles in Ordnung, aber Sie wollen

die Syntax zu verwenden, um der Lage sein,
someFoo.Clone() 

statt

someFoo.Clone<int>() 

Sie die int wollen eher impliziert werden, als es zu setzen, die Ther ausdrücklich ?

Der Grund, warum Sie das in Ihrem Codebeispiel nicht tun können, ist, dass IFoo nicht auf den generischen Typ T verweist, den Sie benötigen, um Bar<T> zu erstellen.

Ich würde vorschlagen, dass Sie wirklich eine andere Schnittstelle benötigen: IFoo<T>

Wenn Sie hatte das, und Ihre Erweiterungsmethode sieht wie folgt aus:

public static Bar<T> Clone<T>(this IFoo<T> foo) 
{ 
    return new Bar<T>(foo); 
} 

Dann haben Sie kein Problem mit

IFoo<int> someFoo = new Foo<int>(); 
Bar<int> someBar = someFoo.Clone(); 

Hoffe, dass hilft