2014-12-03 10 views
7

Próbuję przenieść zestaw SDK napisany w języku Java do języka C#.Odpowiednik anonimowej klasy języka Java w języku C#?

W tym oprogramowaniu istnieje wiele interfejsów "handler" z kilkoma metodami (na przykład: attemptSomethingHandler z success() i kilkoma różnymi metodami awaryjnymi). Ten interfejs jest następnie implementowany i tworzony anonimowo w ramach klasy wywołującej i przekazywany do metody attemptSomething klasy SomethingModel. Jest to metoda asynchroniczna i ma kilka miejsc, w których może zawieść lub wywołuje inną metodę (przekazując procedurę obsługi). W ten sposób anonimowa implementacja attemptSomethingHandler może odwoływać się do prywatnych metod w klasie, która wywołuje attemptSomething.

W języku C# nie można anonimowo zaimplementować interfejsu. Mogłem jawnie zaimplementować nową klasę, ale ta implementacja byłaby unikalna dla tej klasy wywołującej i nie była używana do niczego innego. Co ważniejsze, nie byłbym w stanie uzyskać dostępu do prywatnych metod w klasie telefonicznej, której potrzebuję i nie chcę upubliczniać.

Zasadniczo muszę uruchomić inny kod z klasy wywołującej, w zależności od tego, co dzieje się w metodach klasy SomethingModel.

Czytałem delegatów, ale wymagałoby to przekazania jak największej liczby delegatów, ponieważ istnieją metody w interfejsie obsługi (o ile wiem). Jaki jest odpowiedni sposób to zrobić w języku C#? Czuję, że brakuje mi bardzo wspólnej strategii programowania. Po prostu musi istnieć łatwy i czysty sposób na uporządkowanie i rozwiązanie tego problemu.

+10

Być może warto zilustrować swoje pytanie za pomocą kodu Java, który próbujesz przesłać, a jak do tej pory próbowałeś? –

+0

Twoje pytanie jest niejasne, więc nie będę jeszcze VTC, ale możesz sprawdzić http://stackoverflow.com/questions/191013/can-ac-sharp-anonymous-class-implement-an-interface –

+1

You może implementować interfejs w wewnętrznej klasie. W ten sposób możesz uzyskać dostęp do prywatnych członków klasy dzwoniących. –

Odpowiedz

8

W języku C# nie mamy anonimowych typów takich jak Java jako taka. Można utworzyć typ anonimowy, które zawiera pola tak:

var myObject = new { Foo = "foo", Bar = 1, Quz = 4.2f }

Jednak te nie mogą mieć metody umieszczone w nich i są przejezdne tylko do metod przy użyciu object lub dynamic (ponieważ nie mają one typ na compile- czas, są one generowane przez kompilator AFAIK)

Zamiast tego w języku C# używamy, jak powiedziałeś, delegatów lub lambd.

Jeśli Rozumiem marynatę poprawnie, mógłby zaimplementować zagnieżdżone klasy prywatnej tak:

interface IMyInterface 
{ 
    void Foo(); 
} 

class MyClass 
{ 
    public void Bar() 
    { 
     var obj = new MyInterface(); 
     obj.Foo(); 
    } 

    private class MyInterface : IMyInterface 
    { 
     public void Foo() 
     { 
      // stuff 
     } 
    } 
} 

Teraz MyClass można utworzyć instancję MyInterface który implementuje IMyInterface. Jak wspomnieli komentatorzy, MyInterface może uzyskać dostęp do członków MyClass (chociaż z całą pewnością chcesz spróbować i trzymać się publicznie dostępnych członków obu typów).

To zamyka klasę "anonimową" (używając tutaj terminów Java, aby ją uprościć), a także oznacza, że ​​możesz potencjalnie zwrócić MyInterface jako IMyInterface, a reszta oprogramowania nie będzie mądrzejsza. Tak właśnie działają niektóre abstrakcyjne wzorce fabryczne.


Zasadniczo trzeba uruchomić inny kod z klasy wywołującego w zależności od tego, co dzieje się w metodach klasy SomethingModel.

To pachnie ciężkim sprzężeniem. O jej!

Wydaje mi się, że Twój szczególny problem mógł zostać wykorzystany przy refaktoryzacji. W języku C# możesz może użyć zdarzeń, aby rozwiązać ten problem (uwaga: może, nie powinien). Wystarczy wydarzenie dla każdego punktu "oddziału" swojej metody. Muszę jednak powiedzieć, że to sprawia, że ​​twoje rozwiązanie jest trudniejsze do przewidzenia i utrzymania.

Sugeruję jednak, abyś zaprojektował swoje rozwiązanie w taki sposób, że nie potrzebujesz takiego ciężkiego sprzęgła.

Można również spróbować użyć modelu Pipeline, ale nie jestem pewien, jak to zaimplementować. Wiem, że pomost (czy też jest to Netty - NIO dla Javy JBOSSa) z pewnością użył podobnego modelu.

Może się okazać, że wyrzucenie niektórych testów jednostkowych w celu przetestowania oczekiwanej funkcjonalności klasy ułatwi zaprojektowanie rozwiązania (TDD).

+1

"chociaż z całą pewnością chcesz spróbować i trzymać się publicznie dostępnych członków obu typów" Dlaczego? – weston

+0

Sprzęgło. Chociaż przypuszczam, że w tym przypadku jest to dyskusyjne, ponieważ jest to prywatna klasa zagnieżdżona. Osobiście starałbym się unikać używania prywatnych metod z zagnieżdżonej klasy, gdybym mógł tego uniknąć - to nie jest to, co jest prywatne. Prawdopodobnie powinienem był wspomnieć, że chodzi o unikanie używania prywatnych metod, zamiast unikania używania wewnętrznego/chronionego, z poziomu zagnieżdżonej klasy. Również zakładam, że biorąc pod uwagę, że implementujesz interfejs jako klasę zagnieżdżoną, nie chcesz dotykać prywatnych metod klasy zagnieżdżonej od rodzica. –

+0

Dzięki za odpowiedź. Jak na przykładzie przy użyciu zagnieżdżonej klasy prywatnej: IMyInterface może wymagać implementacji na różne sposoby w różnych klasach. Tak więc Foo() może potrzebować dostępu do instancji MyClass i parametrów przekazanych do Bar() tutaj. Ale w innym miejscu może wymagać innych parametrów itp. Brzmi to jak poprawne, a moje rozwiązanie wymaga poważnego refaktoryzacji. Myślenie, że mogę zachować tę samą strukturę, co implementacja java, prawdopodobnie była głupia :) Brzmi jakbym mógł używać zdarzeń. W niektórych przypadkach te zdarzenia musiałyby zostać zaimplementowane przez osoby korzystające z SDK, czy to możliwe? – bkjvbx

6

Korzystanie delegaci:

void AttemptSomethingAsync(Action onSuccess, Action<string> onError1, Action onError2 = null) { 
    // ... 
} 

// Call it using: 

AttemptSomethingAsync(onSuccess:() => { Yes(); }, onError1: (msg) => { OhNo(msg); }); 

Lub przy klasę

class AttemptSomethingHandler { 
    Action OnSuccess; 
    Action<string> OnError1; 
    Action OnError2; 
} 

void AttemptSomethingAsync(AttemptSomethingHandler handler) { 
    // ... 
} 

// And you call it like 
AttemptSomethingAsync(new AttemptSomethingHandler() { 
     OnSuccess =() => { Yes() }; 
}); 

lub zdarzeń

public delegate void SuccessHandler(); 
public delegate void ErrorHandler(string msg); 

class SomethingModel { 
    public event SuccessHandler OnSuccess; 
    public event ErrorHandler OnError1; 

    public void AttemptSomethingAsync() { 
     // ... 
    } 
} 

// Use it like 

var model = new SomethingModel(); 
model.OnSuccess += Yes; 
model.AttemptSomethingAsync(); 

private void Yes() { 
} 
1

Można użyć klas zagnieżdżonych symulować anonimowych klas, ale w celu wykorzystania zagnieżdżone klasy w taki sam sposób, jak Java, musisz przekazać odwołanie do zewnętrznej klasy. W Javie wszystkie zagnieżdżone i anonimowe klasy mają to domyślnie, a tylko statyczne nie.

interface IMyInterface 
{ 
    void Foo(); 
} 

class MyClass 
{ 
    public void Bar() 
    { 
     IMyInterface obj = new AnonymousAnalog(this); 
     obj.Foo(); 
    } 

    private class AnonymousAnalog : IMyInterface 
    { 
     public void Foo(MyClass outerThis) 
     { 
      outerThis.privateFieldOnOuter; 
      outerThis.PrivateMethodOnOuter(); 
     } 
    } 

    ... 
} 
+0

Zagnieżdżone klasy mogą uzyskać dostęp do instancji klasy nadrzędnej, która je utworzyła za pomocą 'OuterClass.this'. – Samah

Powiązane problemy