为非线程安全类创建一个可观察的包装器

时间:2011-08-15 21:40:03

标签: c# system.reactive

我有一个班级,

public class Test
{
  public int Calc();
}

要求所有对Calc的调用都在与创建Test的线程相同的线程上执行。我需要创建一次测试(昂贵的操作)并多次调用Calc。

我想要一个包装器让我可以异步调用Calc:

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

一种方法是创建BackgroundWorker或Thread,并将其用作Test的所有操作都在同一个线程上的保证。为简单起见,我们可以假设所有对Calc()的调用都将按顺序执行,因此无需担心排队。

有更优雅的RX方式吗?

3 个答案:

答案 0 :(得分:4)

如果在创建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本身的同一个线程上处理的(即调用线程)。

答案 1 :(得分:3)

所以从评论和重新阅读你的问题我收集到你想要在一个常量线程上重复调用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;
    });
  }
}

答案 2 :(得分:0)

在创建Test的实例时使用ThreadLocal<T>课程:

var MyTEST = new ThreadLocal<Test>();

然后您可以使用MyTEST.Value.Calc ()进行任何通话......

另一个选择是在包装类的Test成员上使用put [ThreadStatic] ... 见http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx

根据您是否需要多个Test个实例,您可以将其设为Singleton