2009-12-17 3 views
16

Ich habe einige Klassen, die nicht eine bestimmte Schnittstelle implementieren, aber strukturell dieser Schnittstelle entsprechen.Automatisches Erstellen eines Wrappers zur Implementierung einer Schnittstelle

interface IFoo { 
    void method(); 
} 

class Bar { // does not implement IFoo 
    public void method() {...} 
} 

Nun könnte ich einen Wrapper um die Klassen schreiben, die einfach auf die gewickelten Klasse delegieren

class BarWrapper : IFoo { 
    Bar bar = new Bar(); 
    public void method() 
    { 
     bar.method(); 
    } 
} 

Aber das ist viel mühsamer Arbeit. Können diese Wrapper-Klassen irgendwie automatisch generiert werden? Etwas wie:

IFoo foo = CreateWrapper<IFoo>(new Bar());

Ich bin sicher, dass Sie dies mit Reflection.Emit tun könnte, aber ich habe noch nie verwendet, dass und es sieht nicht sehr einfach, auf den ersten Blick.

Gibt es einen einfacheren Weg oder gibt es vielleicht eine Bibliothek, die dies bereits implementiert?

+0

Wenn Sie am Ende zu schreiben es selbst, könnte dies als ein verwandtes Beispiel helfen: http://stackoverflow.com/questions/847809/how-can-i-write-a-generic-container-class-that-implements-a-given-interface-in -c/847975 # 847975 –

Antwort

2

Sie könnten sich die DynamicProxy von Castle Project ansehen. Das verwendet Rhino.Mocks für seinen Proxy-Typ.

Ich habe es selbst nicht benutzt, also weiß ich nicht, wie viel Aufwand es von Ihrer Seite erfordert, aber ich vermute, dass es ein guter Ausgangspunkt ist.

+0

AFAIK, die aktuelle Version von Dynamic Proxy funktioniert nur Schnittstellen und konkrete Typen und kann nur virtuelle Methoden abfangen. Es macht kein Mapping. Es könnte jedoch in Zukunft darauf eingehen: http://using.castleproject.org/display/CASTLE/Dynamic+Proxy+3+design+meeting (scrollen Sie nach unten zu "Type Wrapping") –

+0

@Mark: Die Frage erwähnt nur mit Interfaces arbeiten, das klingt für mich nicht nach einer wesentlichen Einschränkung. –

+0

@Jon Skeet: Ja, aber er möchte eine konkrete Klasse, die weder eine Schnittstelle implementiert noch virtuelle Methoden enthält, in eine Proxy-Klasse einbinden. Daher halte ich sie für sehr relevant. –

0

Wenn Sie bereit sind, .NET 4 zu verwenden, könnte eine Lösung die Wrapperklasse als DynamicObject definieren und die Aufrufe der dynamischen Methoden in Aufrufe der umschlossenen Klasse mithilfe der Reflektion konvertieren (ich bin mir nicht sicher wenn das tatsächlich weniger Arbeit wäre, berücksichtigen Sie auch mögliche Leistungsbedenken, die mit der Verwendung von Reflektion verbunden sind.

0

Obwohl ich sie selbst nicht verwendet habe, denke ich, dass T4-Vorlagen in Visual Studio für die Codegenerierung der dynamischen Typen link text verwendet werden können.

0

Hier ist ein etwas anderer Ansatz mit Generika. Dies würde ein wenig mehr Arbeitsgedanke erfordern. Sie müssen für jede Schnittstelle einen Wrapper implementieren und alle Methoden mit Reflektion aufrufen.

class FooWrapper<T> : IFoo 
{ 
    private T obj; 

    public FooWrapper(T obj) 
    { 
     this.obj = obj; 
    } 

    public void method() 
    { 
     // call method with reflection 
     // obj.method(); 
    } 
} 

IFoo foo = new FooWrapper(new Bar()); 
+0

+1: würde das gleiche tun. Plus einige Reflexion Cache hinzufügen, um die Leistungseinbußen durch die Suche nach Methoden durch Reflexion hinzugefügt zu minimieren –

+1

Gute Idee, aber wenn Sie Reflection verwenden, dann können Sie auch für einige vorhandene Enten tippen Lösungen gehen. Am Ende würden Sie aus Performance-Gründen den IL-Code senden und das Rad neu erfinden. – Groo

8

Was Sie versuchen zu erreichen, ist als Ente Typisierung bekannt. Es gibt einige dedizierte Bibliotheken, mit denen Sie das tun können, obwohl ich keine davon benutzt habe.

Mit wenig Aufwand (und ein wenig Nachdenken) können Sie Castle Dynamic Proxy dazu verwenden, indem Sie den Ansatz here verwenden.

Wenn aus irgendeinem Grund der Interceptor-basierte Ansatz für Sie nicht akzeptabel wäre, unterstützt Dynamic Proxy dies (noch) nicht, aber wenn Sie Version 2.2 Beta verwenden, wäre es ziemlich einfach, dies in einem bereitzustellen stark typisierte Art und Weise (ohne Verwendung von Interzeptoren), indem Sie Ihren eigenen Proxy-Typ-Builder bereitstellen (schauen Sie sich an, wie Mixins implementiert werden).

+1

+1 Danke für den Beitritt :) –

3

Sie könnten eine neue Klasse erstellen

class SubBar : IFoo, Bar { 
} 

und instanziiert, dass (Unter der Annahme Bar wirklich die ducktype hat, das heißt, die genauen IFoo Methoden).

5

Wenn Sie leichte und einfache Duck Tippen Unterstützung möchten, können Sie auch überprüfen: Duck Typing project. Es funktioniert mit .Net 2.0 und neuer.

Anwendungsbeispiel (aus David Meyer's site):

public interface ICanAdd 
{ 
    int Add(int x, int y); 
} 

// Note that MyAdder does NOT implement ICanAdd, 
// but it does define an Add method like the one in ICanAdd: 
public class MyAdder 
{ 
    public int Add(int x, int y) 
    { 
     return x + y; 
    } 
} 

public class Program 
{ 
    void Main() 
    { 
     MyAdder myAdder = new MyAdder(); 

     // Even though ICanAdd is not implemented by MyAdder, 
     // we can duck cast it because it implements all the members: 
     ICanAdd adder = DuckTyping.Cast<ICanAdd>(myAdder); 

     // Now we can call adder as you would any ICanAdd object. 
     // Transparently, this call is being forwarded to myAdder. 
     int sum = adder.Add(2, 2); 
    } 
} 

Mit Erweiterungsmethoden, können Sie es in so etwas wie diese (simlar zu Bart De Smet's Syntax) vereinfachen könnten

MyAdder myAdder = new MyAdder(); // this doesn't implement the interface 
ICanAdd adder = myAdder.AsIf<ICanAdd>(); // but it quacks like a duck 
int sum = adder.Add(2, 2); 
Verwandte Themen