2013-03-18 10 views
7

Ist es möglich, eine Klasse aus den Methoden in anderen Klassen dynamisch zu komponieren?Dynamisch komponieren Sie eine Klasse in C#

Zum Beispiel. Die Klassen A, B und C haben öffentliche Methoden, die so benannt sind, dass sie leicht identifiziert werden können. Sie müssen extrahiert und zur Klasse D hinzugefügt werden. Klasse D, die dann die gesamte Implementierungslogik enthält, kann weiter in ein System übertragen werden, das nur eine einzige Instanz der Klasse D akzeptiert und diese Methoden dynamisch an andere Funktionen bindet.

Um klar zu sein, das ist nicht Vererbung, die ich suche. Ich behaupte buchstäblich, dass Methoden mit unterschiedlichen Namen in eine Klasse eingefügt werden müssen. Das System, an das ich es weitergebe, versteht diese Namenskonventionen und bindet sie dynamisch (es ist eine Blackbox für mich).

Ich gehe den Pfad der Extrahierung der Methoden aus A, B und C hinunter, kombiniere sie dynamisch mit der Quelle der Klasse D im Speicher und kompiliere sie in eine neue Klasse D und erstelle dann eine Instanz von D und passiere es vorwärts.

public class A{ public void EXPORT_A_DoSomething(){} } 
public class B{ public void EXPORT_B_DoSomethingElse(){}} 
public class C{ public void EXPORT_C_DoAnything(){}} 
//should become 
public class D{ 
      public void EXPORT_A_DoSomething(){} 
      public void EXPORT_B_DoSomethingElse(){} 
      public void EXPORT_C_DoAnything(){} 
} 

Gibt es eine Möglichkeit, die MethodInfos von Klasse A, B und C und irgendwie direkt befestigen sie an der Klasse D zu extrahieren? Wenn das so ist, wie?

+3

Sie können den Code Ihrer Klasse in eine einfache Textdatei ausgeben, speichern und zur Laufzeit kompilieren. Werfen Sie einen Blick auf die [CSharpCodeProvider-Klasse] (http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx) und verwandte Themen, um zu erfahren, wie Sie dies tun. –

+1

Soweit ich weiß, gibt es keine Möglichkeit, die Implementierung einer Methode zu kopieren. Ich würde wahrscheinlich eine DynamicObject-abgeleitete Klasse erstellen, die Instanzen von A, B und C enthält, und dann die von DynamicObject abgeleiteten Klassenimplement-Methoden mit diesen Namen verwenden und sie einfach den enthaltenen Objekten zuweisen. Das vorausgesetzt, ich verstehe, was Sie fragen. Ich denke, das würde funktionieren. – Pete

+1

@JohnWillemse: Multicast-Delegaten, wenn Ihre Methoden die gleiche Signatur teilen, kann hilfreich für Sie sein – TalentTuner

Antwort

2

Ich würde in Betracht ziehen, die C# Class compiler zu verwenden. Soweit ich mich erinnern kann, können Sie Code erstellen, der sich in einer Zeichenfolge befindet, und Sie können eine Assembly als Ausgabe abrufen. Dies ermöglicht Ihnen dann, Methoden durch Reflektion aufzurufen.

Es gibt ein Beispiel auf der MSDN-Verbindung, die ich angegeben habe, aber ich werde einen nach oben für hier vortäuschen, sobald ich mein Projekt finde.

+0

Ich habe Zugriff auf die Quelle der Klassen A/B/C, so scheint die dynamische Kompilierung der direkteste, "Brute-Force" -Ansatz zu sein. Ein weiterer Kommentator brachte die Komplexität der Zusammenführung von privaten Daten in diesen Klassen auf den Prüfstand, eine weitere Hürde. –

-1

Haben Sie in Erwägung gezogen, einfach einen Hash oder eine Liste von Delegaten in Ihrer D-Klasse zu verwenden, die auf die Methoden in den anderen Klassen verweisen? Verwenden Sie alternativ ein dynamisches Objekt (google ExpandoObject).

+0

leider müssen die Methoden durch Reflexion durch das System zugänglich sein, das sie benutzt, also funktioniert es nicht. –

+0

Sie können mit ein wenig zusätzlicher Arbeit noch über dynamische Objekte reflektieren. Ich würde nicht mit Delegierten abschreiben. – pfries

0

Eine andere Lösung ist die Klasse erhalten und setzen Accessoren für die Funktion als Schnittstelle zu definieren und erklären die Funktionen, die Sie interessieren.

interface iA 
{ 
    public int a { get; set; } 
} 
interface iB 
{ 
    public int b { get; set; } 
} 
interface iAB : iA, iB 
{ 
} 
class MyClass : iA, iB 
{ 
    public int b { get; set; } 
    public int a { get; set; } 
} 
static class MyClassExtender 
{ 
    static public int Foo(this iAB ab) 
    { 
     int c = ab.a + ab.b; 
     ab.a = c; 
     return c; 
    } 
    static public int FooA(this iA a) 
    { 
     int c = ab.a + 1; 
     ab.a = c; 
     return c; 
    } 
    static public int FooB(this iB b) 
    { 
     int c = ab.b + 1; 
     ab.a = c; 
     return c; 
    } 

} 

So, jetzt „MyClass“ Foo, FooA verwenden können, und FooB als öffentliche Methoden.

+0

Leider können die Methoden nicht statisch sein. Ich liebe Verlängerungsmethoden, aber in diesem speziellen Fall würden sie nicht funktionieren. Die Methoden müssen öffentliche Instanzmitglieder sein. –

+0

Nur aus Neugier, was verhindert diese Funktion? Sie können Nebenwirkungen mit den oben genannten Methoden verursachen und interne Schnittstellen verwenden, um Dinge außerhalb des Moduls zu verbergen. Es erzeugt eine große Bandbreite von Schnittstellen, daher bin ich mir nicht sicher, wie wartbar das Designmuster ist. – IdeaHat

0

Es sollte eigentlich möglich sein mit etwas namens "Mixins" und Proxy-Generatoren. Werfen Sie einen Blick auf Castle.DynamicProxy Tutorial: Mixins

1

Sie können nicht nur die Methoden exportieren. Die Methoden können nicht wirklich von der Klasse getrennt werden, in der sie sich befinden. (Sie benötigen Zugriff auf alle Mitgliedsfelder/Eigenschaften einschließlich geerbt).

Ich denke, das einzige, was Sie tun können, ist eine Schnittstelle zu implementieren. (Obwohl Sie sagen, dass es nicht das ist, was Sie brauchen, sehe ich keinen Weg um den privaten Status für diese Objekte zu benötigen)

Sie können eine einzelne Schnittstelle erstellen, die nur die Methoden enthält, die Sie benötigen, und eine Klasse bereitstellen, die unterstützt es, das eine Instanz jedes Objekttyps enthält.

public class A{ public void DoSomething(){} } 
public class B{ public void DoSomethingElse(){}} 
public class C{ public void DoAnything(){}} 

public interface ID 
{ 
    void A_DoSomething(); 
    void B_DoSomethingElse(); 
    void C_DoAnything(); 
} 

public class D : ID 
{ 
    private A a; 
    private B b; 
    private C c; 

    public D(A a,B b, C c) { this.a=a;this.b=b;this.c=c; } 

    public void A_DoSomething(){ a.DoSomething();} 
    public void B_DoSomethingElse(){ b.DoSomethingElse();} 
    public void C_DoAnything(){ c.DoSomething(); 
} 

Wenn Sie dies dynamisch generieren müssen, schauen Sie in Reflection.Emit. Es wird etwas darüber gehen, wie Sie eine neue Assembly erstellen und dann dynamisch in die AppDomain laden müssen. Ich würde versuchen, das zu vermeiden, wenn du kannst.

+0

Ich kann dies als eine Lösung sehen, obwohl, wenn wir über potenziell Hunderte von Methoden sprechen, es definitiv dynamisch getan werden müsste. Ich sehe eine menschliche Upkept-Version, bei der andere Entwickler die Interface-ID für jede benötigte Methode beibehalten - aber Mann, was für ein Durcheinander wäre das. Ich mag die "Durchreichbarkeit" des von Ihnen vorgeschlagenen Codes. Eine der Ideen, die ich hatte, war ein Hybrid. Ich schreibe Stubs dynamisch in Klasse D, die Aufrufe von Klasse A, B, C usw. sind. Ich denke, mit einer Schnittstelle können Sie Methodenimplementationen direkt über codedom anhängen. –

+0

Vielleicht könnten Sie eine T4-Vorlage verwenden, um so etwas zu generieren. Es wäre nicht dynamisch wie in 'zur Laufzeit geladen', aber es kann die Belastung erleichtern, eine Menge Klempnercode zu schreiben. –

Verwandte Themen