ObservableAsPropertyHelper - 必须访问 Value 才能订阅? [英] ObservableAsPropertyHelper - have to access Value to get it to subscribe?

查看:44
本文介绍了ObservableAsPropertyHelper - 必须访问 Value 才能订阅?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近将我的 ReactiveUI 块包更新到了​​最新的预发布版本 (v5.99.4-beta).我已经有一段时间没有更新了,但我对 ViewModel 的许多测试都失败了.

I recently updated my ReactiveUI nugget packages to the latest pre-release versions (v5.99.4-beta). It has been a while since I did the update, but many of my tests on ViewModel's failed.

调试器似乎表明我的正常 Rx 序列没有被订阅.例如:

The debugger seemed to indicate that my normal sequences of Rx weren't getting subscribed to. For example:

  _executeSearch = ReactiveCommand.Create();
  var paper = _executeSearch
              .Where(x => x is string)
              .SelectMany(x => _searchParser.GetPaperFinders(x as string))
              .SelectMany(x => x.FindPaper());
  paper
       .Select(x => x.Item1.Title)
       .ToProperty(this, x => x.Title, out _TitleOAPH, "");

我的测试代码看起来像这样(为简洁起见):

And my tests code looked something like this (cut for brevity):

  INavService obj = Mock...
  ISearchStringParser parser = ...

  var vm = new AddCDSPaperViewModel(obj, parser);
  vm.CDSLookupString = "1234"; // trigger the "search"
  ... (test scheduler is advanced to wait for search results to show up
  Assert.AreEqual("title", vm.Title, "searched for title"); // vm.Title is unset, though it should be!

我查看了github上的reactiveui源代码,发现ObservableAsPropertyHelper对象上的value"属性如下:

I looked at the reactiveui source code on github and discovered the following for the "value" property on the ObservableAsPropertyHelper object:

    public T Value {
        get { 
            _inner = _inner ?? _source.Connect();
            return _lastValue; 
        }
    }

那里的关键行是_source.Connect()"——简而言之,在有人访问 Value 之前,不会订阅该序列.在我的测试中,如果我在运行任何 rx 序列之前放置一个vm.Title",那么一切正常.

The key line there is "_source.Connect()" - in short, the sequence isn't subscribed to until someone access Value. In my tests, if I put a "vm.Title" before I run any rx sequences, then everything works just fine.

这是令人惊讶的行为(至少对我而言),因为在捕获任何值之前必须访问 ObservableAsPropertyHelper.Value 属性.这是预期的行为吗?是否出于效率(例如延迟实例化)原因而完成?如果是这样,在测试中解决此问题的正确方法是什么?

This is surprising behavior (at least to me), in the sense that the ObservableAsPropertyHelper.Value property has to be accessed before it will capture any values. Is this expected behavior? Was it done for efficiency (e.g. lazy instantiation) reasons? If so, what is the proper way around this in tests?

或者我对它的工作方式有很大的误解?:-)

Or am I very mistaken in how this works? :-)

推荐答案

这是预期的行为吗?

Is this expected behavior?

是的,这是 ReactiveUI 6.0 的新功能.

Yep, this is new for ReactiveUI 6.0.

这样做是出于效率(例如延迟实例化)的原因吗?

Was it done for efficiency (e.g. lazy instantiation) reasons?

正确 - 它实际上最终可以节省大量内存和工作!(我记得在 GitHub for Windows 的早期测试中有 15-20% 的内存)

Correct - it actually can end up saving a lot of memory and work! (15-20% memory as I recall in GitHub for Windows on my early tests)

尽管这是一个有趣的场景 - 我怀疑在单元测试运行器中,我们应该订阅构建,类似于 RxUI 5.x 所做的.

This is an interesting scenario though - I suspect that in the unit test runner, we should be subscribing on construction, similar to what RxUI 5.x did.

我会这样写:

_executeSearch = ReactiveCommand.Create(_ => Observable.Return(x)
    .Where(x => x is string)
    .SelectMany(x => _searchParser.GetPaperFinders(x as string))
    .SelectMany(x => x.FindPaper()));

_executeSearch
   .Select(x => x.Item1.Title)
   .ToProperty(this, x => x.Title, out _TitleOAPH, "");

现在,您可以更轻松地编写测试,无需 TestScheduler:

Now, you can write your test way easier, without TestScheduler:

var vm = new AddCDSPaperViewModel(obj, parser);
var result = await vm.ExecuteSearch.ExecuteAsync("Some String");
Assert.AreEqual("title", result.Title);

这篇关于ObservableAsPropertyHelper - 必须访问 Value 才能订阅?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆