Создайте наблюдаемую оболочку для класса, не поддерживающего потоки - PullRequest
8 голосов
/ 16 августа 2011

У меня есть класс,

public class Test
{
  public int Calc();
}

, который требует, чтобы все вызовы Calc выполнялись в том же потоке, что и тот, в котором был создан Test.Мне нужно создать Test один раз (дорогостоящая операция) и несколько раз вызвать Calc.

Мне бы хотелось иметь обертку, которая позволит мне вызывать Calc асинхронно:

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

Один способсделать это будет создать BackgroundWorker или поток и использовать его как гарантию того, что все операции в тесте выполняются в одном потоке.Для простоты можно предположить, что все вызовы Calc () будут выполняться последовательно, поэтому не нужно беспокоиться об организации очередей.

Есть ли более элегантный способ RX сделать это?

Ответы [ 3 ]

4 голосов
/ 16 августа 2011

Если возможно создать Test при создании TestWrapper, то этот класс, кажется, соответствует вашим требованиям:

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

Используется так:

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

Я протестировал его, и он создает Test в том же потоке, в котором выполняется Calc. Подписка, с другой стороны, обрабатывается в том же потоке, в котором был создан сам testWrapper (то есть вызывающий поток).

3 голосов
/ 16 августа 2011

Итак, из комментариев и перечитывания вашего вопроса я понимаю, что вы хотите многократно вызывать Calc () для постоянной цепочки и иметь возвращаемые результаты в виде IObservable<Int>()?

В этом случае я бы использовал Observable.Create, чтобы обернуть класс Test, и EventLoopScheduler, чтобы убедиться, что вызовы Calc выполняются в одном потоке.

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 голосов
/ 16 августа 2011

используйте класс ThreadLocal<T> при создании вашего экземпляра Test:

var MyTEST = new ThreadLocal<Test>();

, тогда вы можете использовать MyTEST.Value.Calc () для любых вызовов ...

Другим вариантом является использование put [ThreadStatic] на элементе Test класса оболочки ... см. http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx

В зависимости от того, требуется ли вам более одного экземпляра Test, вы можете сделать его Синглтон .

...