2011-08-15 7 views
8

Mam klasy,Załóż zaobserwowania opakowanie do bezpiecznego non wątku klasy

public class Test 
{ 
    public int Calc(); 
} 

który wymaga, aby wszystkie połączenia do Calc być wykonywane w tym samym wątku jak ten, na którym test został stworzony. Muszę utworzyć test raz (kosztowna operacja) i wielokrotnie wywołać funkcję Calc.

Chciałbym mieć opakowanie, które pozwoli mi zadzwonić Calc asynchronousely:

public class TestWrapper 
{ 
    private Test _test; 
    public IObservable<int> Calc(); 
} 

Jednym ze sposobów byłoby stworzyć BackgroundWorker lub wątek i używać go jako gwarancję, że wszystkie operacje na Test są w tym samym wątku. Dla uproszczenia możemy założyć, że wszystkie wywołania funkcji Calc() będą wykonywane sekwencyjnie, więc nie trzeba się martwić o kolejkowanie.

Czy jest bardziej elegancki sposób RX to zrobić?

Odpowiedz

4

Jeśli to możliwe Test zostać utworzony podczas TestWrapper powstaje wtedy klasa ta wydaje się spełniać swoje wymagania:

public class TestWrapper 
{ 
    public TestWrapper(Func<Test> factory) 
    { 
     _scheduler = new EventLoopScheduler(); 
     _test = Observable.Start(factory, _scheduler).First(); 
    } 

    private readonly EventLoopScheduler _scheduler; 
    private readonly Test _test; 

    public IObservable<int> Calc() 
    { 
     return Observable.Start(() => _test.Calc(), _scheduler); 
    } 
} 

jest on stosowany tak:

var testWrapper = new TestWrapper(() => new Test()); 
testWrapper.Calc().Subscribe(x => { }); 

I ve przetestował to i tworzy Test w tym samym wątku, który jest wykonywany na Calc. Z drugiej strony subskrypcja jest obsługiwana w tym samym wątku, w którym utworzono samą testWrapper (tj. Wątek wywołujący).

3

Po komentarzu i ponownym przeczytaniu pytania, które zebrałem, chcesz wielokrotnie wywoływać funkcję Calc() na stałym wątku i mieć wyniki zwracania dostępne jako IObservable<Int>()?

W tym przypadku użyłbym Observable.Create, aby zawinąć klasę Test, i EventLoopScheduler, aby upewnić się, że wywołania do Calc są w jednym wątku.

public class TestWrapper 
{ 
    private Test _test; 
    public IObservable<int> Calc() 
    { 
    return Observable.Create(obsvr => 
    { 
     var fixedThreadsched = new EventLoopScheduler(); 
     var disp = new BooleanDisposable(); 
     while (!disp.IsDisposed) 
     { 
      fixedThreadsched.Schedule(() => obsvr.OnNext(_test.Calc())); 
     } 

     return disp; 
    }); 
    } 
} 
+0

Dzięki, EventLoopScheduler jest kluczem do przekazywania połączeń do tego samego wątku. Mimo to ta odpowiedź nie wyjaśnia, jak przełączyć z TestWrapper.Calc, który będzie wykonywany na wątku UI do testowania.Calc ... –

+0

@Sergey - Zaktualizowano na podstawie komentarzy –

+0

Jest bliżej ... Brakuje części nie twórz _test (co powinno zostać wykonane na EventLoopScheduler). Hmm ... Trudno zdecydować - byłeś pierwszy z EventLoopScheduler, ale @enigmativity dostarczył poprawną odpowiedź. Dziękuję wam oboje rock! –

Powiązane problemy