2013-03-18 11 views
7

Czy można dynamicznie komponować klasę z metod zawartych w innych klasach?Dynamicznie skomponuj klasę w języku C#

Na przykład. Klasy A, B i C mają publiczne metody nazwane tak, że można je łatwo zidentyfikować. Muszą one zostać wyodrębnione i dodane do klasy D. Klasa D, która następnie zawiera całą logikę implementacji, może zostać przekazana dalej do systemu, który akceptuje tylko pojedyncze wystąpienie klasy D i dynamicznie wiąże te metody z innymi funkcjami.

Dla jasności, nie jest to dziedziczenie, którego szukam. Dosłownie stwierdzam, że metody o różnych nazwach muszą być wpakowane w jedną klasę. System, przez który go przekazuję, rozumie te konwencje nazewnictwa i dynamicznie je wiąże (to dla mnie czarna skrzynka).

Idę na ścieżkę wyodrębniania metod z A, B i C, dynamicznie łącząc je ze źródłem klasy D w pamięci i kompilując je w nową klasę D, a następnie tworząc instancję D i przechodząc to do przodu.

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(){} 
} 

Czy istnieje sposób, aby wyodrębnić MethodInfos z klasy A, B i C, a jakoś bezpośrednio dołączyć je do klasy D? Jeśli tak to jak?

+3

Możesz wypisać kod swojej klasy do pliku tekstowego, zapisać go i skompilować w czasie wykonywania. Spójrz na [Klasa CSharpCodeProvider] (http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx) i pokrewne tematy, aby dowiedzieć się, jak to zrobić. –

+1

O ile mi wiadomo, nie ma sposobu na skopiowanie implementacji metody. Najprawdopodobniej utworzę klasę pochodną DynamicObject, która będzie zawierała instancje A, B i C, a następnie będzie miała metody imlpementowe klasy pochodnej DynamicObject o tych nazwach i po prostu będzie je proxy dla zawartych obiektów. Zakładając, że rozumiem, o co prosisz. Myślę, że to by działało. – Pete

+1

@JohnWillemse: Multicast deleguje, jeśli twoje metody dzielą ten sam podpis, może ci pomóc – TalentTuner

Odpowiedz

2

Chciałbym rozważyć użycie C# Class compiler. Z tego, co pamiętam, można zbudować kod, który jest w ciągu znaków i można uzyskać złożenie jako wynik. To pozwala na wywoływanie metod poprzez odbicie.

Istnieje przykład linku MSDN podanego przeze mnie, ale skopię go tutaj, gdy znajdę swój projekt.

+0

Mam dostęp do źródła klas A/B/C, więc dynamiczna kompilacja wydaje się być najbardziej bezpośrednią, "brutalną siłą". Inny komentujący poniżej podniósł złożoność łączenia prywatnych danych w ramach tych klas, co stanowi kolejną przeszkodę. –

-1

Czy zastanawiałeś się po prostu używając skrótu lub listy delegatów w twojej klasie D, które wskazują metody na innych zajęciach? Alternatywnie użyj obiektu dynamicznego (google ExpandoObject).

+0

Niestety, metody muszą być dostępne za pośrednictwem refleksji przez system, który ich użyje, więc to nie zadziała. –

+0

Nadal można zastanowić się nad dynamicznymi obiektami przy odrobinie dodatkowej pracy. Nie odpisałbym za pomocą delegatów. – pfries

0

Innym rozwiązaniem jest zdefiniowanie klasy pobrać i ustawić akcesorów dla funkcji jako interfejs i deklarować funkcje Cię interesują.

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; 
    } 

} 

Więc teraz „MojaKlasa” mogą korzystać Foo FooA i FooB jako publiczne metody.

+0

Niestety, metody nie mogą być statyczne. Uwielbiam metody rozszerzania, ale w tym konkretnym przypadku nie działałyby. Metody muszą być członkami publicznych wystąpień. –

+0

Po prostu z ciekawości, jaka jest funkcja, która uniemożliwia ich działanie? Możesz powodować działania niepożądane za pomocą powyższych metod i można używać wewnętrznych interfejsów, aby ukryć elementy poza modułem. Tworzy ogromną liczbę interfejsów, więc nie jestem pewien, jak można utrzymać wzór projektu. – IdeaHat

0

Powinno być możliwe użycie czegoś, co nazywa się "Mixins" i generatorów proxy. Zapoznaj się z samouczkiem Castle.DynamicProxy: Mixins

1

Nie będziesz mógł eksportować tylko tych metod. Metody nie można tak naprawdę oddzielić od klasy, w której się znajdują (potrzebują dostępu do wszystkich pól członkowskich/właściwości, w tym dziedziczonych).

Myślę, że jedyną rzeczą, którą możesz zrobić, to wydać implementację interfejsu. (nawet jeśli mówisz, że to nie jest to, czego potrzebujesz, nie widzę sposobu, aby potrzebować prywatnego stanu dla tych obiektów).

Możesz utworzyć pojedynczy interfejs, który zawiera tylko potrzebne metody, i zapewnić klasę, która obsługuje to, które zawiera instancję każdego typu obiektu.

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(); 
} 

Jeśli potrzebujesz generować to dynamicznie, zajrzyj do Reflection.Emit. Będzie to trochę interesować, w jaki sposób utworzyć nowy zespół, a następnie załadować go dynamicznie do AppDomain. Chciałbym tego uniknąć, jeśli możesz.

+0

Rozumiem, że jest to rozwiązanie, ale gdy mówimy o potencjalnie setkach metod, zdecydowanie trzeba by to zrobić dynamicznie. Mogę zobaczyć ludzką wersję, w której inni programiści zachowują identyfikator interfejsu dla każdej metody, którą dodali, dodając - ale co to za bałagan. Podoba mi się "pass-through" proponowanego kodu. Jedną z moich pomysłów była hybryda. Dynamicznie wypisywanie skrótów do klasy D, które są wywołaniami do klasy A, B, C itd. Myślę, że użycie interfejsu umożliwia bezpośrednie dołączanie implementacji metod za pomocą codedom. –

+0

Może mógłbyś użyć szablonu t4 do wygenerowania czegoś takiego. Nie byłoby dynamiczne, jak w "załadowanym w czasie pracy", ale może zmniejszyć obciążenie pisania wielu kodów instalacyjnych. –

Powiązane problemy