【问题标题】:RX Best Practice: Select with side-effect or use subscribe?RX 最佳实践:选择有副作用还是使用订阅?
【发布时间】:2015-01-05 21:44:10
【问题描述】:

我将事件(来自按钮的分页事件)转换为 IObservable 并异步接收来自服务的结果。

作为副作用,我必须更新子视图。我有两个解决方案:

  1. 选择中的副作用:

        //Converting events to a "stream" of search results.
        IObservable<SearchResult> resultsFromPageChange = Observable.FromEventPattern<EventArgs>(this,
            "PageChangedEvent")
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async ev =>
             {
                 var input = new SearchResultInput()
                 {
                     PageSize = PageSize,
                     PageIndex = PageIndex,
                     SearchOptions = _currentSearchOptions,
                     SearchText = SearchText.Value
                 };
                 var result = await GetPagedComponents(input);
                 //Side effect
                 ActivateAttributesView(result.Components.FirstOrDefault());
    
                 return result;
             }).Switch(); //flatten and take most recent.
    
  2. 在subsribe中做副作用:

        //Converting events to a "stream" of search results.
        IObservable<SearchResult> resultsFromPageChange = Observable.FromEventPattern<EventArgs>(this,
            "PageChangedEvent")
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async ev =>
            {
                var input = new SearchResultInput()
                {
                    PageSize = PageSize,
                    PageIndex = PageIndex,
                    SearchOptions = _currentSearchOptions,
                    SearchText = SearchText.Value
                };
                return await GetPagedComponents(input);
            }).Switch(); //flatten and take most recent.
    
        //Do side effect in the subscribe
        resultsFromPageChange.Subscribe(x =>
        {
            if (x != null)
                ActivateAttributesView(x.Components.FirstOrDefault());
        });
    

这两种方法都有效。我应该选择哪种解决方案?为什么?

谢谢。

因为有问题为什么这会产生值,所以这里是完整的代码:

        //Converting events to a "stream" of search results.
        IObservable<SearchResult> resultsFromPageChange = Observable.FromEventPattern<EventArgs>(this,
            "PageChangedEvent")
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async ev =>
            {

                var input = new SearchResultInput()
                {
                    PageSize = PageSize,
                    PageIndex = PageIndex,
                    SearchOptions = _currentSearchOptions,
                    SearchString = SearchString.Value
                };

                return await SearchComponentsPaged(input);

            }).Switch(); //flatten and take most recent.

        SearchString = new ReactiveProperty<string>(""); //Bound to TextBox.Text 

        //Create a "stream" of search results from a string given by user (SearchString)
        SearchResult = SearchString
            .SetValidateNotifyError(s => _componentDataService.ValidateSearchStringLength(s).Errors)
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async term =>
            {
                var input = new SearchResultInput()
                    {
                        PageSize = PageSize,
                        PageIndex = PageIndex,
                        SearchOptions = _currentSearchOptions,
                        SearchString = term
                    };

                return await SearchComponentsPaged(input);

            })
            .Switch()
            .Merge(resultsFromPageChange) //Merge the result of paging and text changing.  
            .ToReactiveProperty();

        //Update Attributes view
        SearchResult.Subscribe(searchResult =>
        {
            if (searchResult != null)
            {
                ActivateAttributesView(searchResult.Components.FirstOrDefault());
                SearchResult.Value.TotalItemsCount = searchResult.TotalItemsCount;
            }

        });

它的实际作用是在搜索字符串更改时向数据库发送搜索请求并获取分页结果,或者在收到 PageChangedEvent 时获取具有相同搜索字符串的另一个页面。 .Merge(...) 是订阅吗?

【问题讨论】:

  • 对于您的第一个解决方案,如果没有订阅,ActivateAttributesView 会被调用吗?
  • 嗯,我不知道“如果没有订阅”到底是什么意思。我所知道的是,对于解决方案 2,我必须明确检查是否为空。我不必使用解决方案 1 检查这一点。
  • -- 没关系,我没有意识到您正在使用基于 TaskSwitch 重载。
  • 为什么一种解决方案有时会产生您必须防范的空值,而另一种则不会?此外,除非您订阅,否则解决方案 1 实际上不会做任何事情,即使您没有提供订阅回调(例如 .Switch().Subscribe()),这是因为 FromEventPattern 在您订阅之前实际上不会注册事件处理程序。
  • 我不明白为什么会有空的结果。我不订阅它。但是我将这个“流”与另一个合并。那是订阅吗?我不知道。我将编辑示例以显示更多我的实际(工作)代码。

标签: c# system.reactive


【解决方案1】:

我会选择你的第二个解决方案。它更加灵活,因为不同的订阅者可以选择具有不同的副作用。它还分离了关注点,Rx 查询生成数据,订阅者随意使用数据。

【讨论】:

  • 好点。我会稍等片刻接受这个答案,看看有没有其他意见。
  • 如果您不必大幅扭曲代码以使其无副作用,那么请继续使用第二种方式——您将拥有更灵活/可维护的代码。它也更容易推理 - 需要更少的搜索来找到实际上具有副作用的代码,因为大多数开发人员看到 WhereSelect 并假设它没有副作用。他们倾向于寻找foreach(用于LINQ)或Subscribe(用于Rx)来寻找副作用。
【解决方案2】:

这是 select 和 where to be pure functions(无副作用)的最佳实践。它更清楚地表明了意图。

此外,由于 observables 是可组合的,并且您可能希望在其他地方再次使用数据流,因此最好尽可能明确地说明副作用。

【讨论】:

    猜你喜欢
    • 2020-06-04
    • 1970-01-01
    • 2018-04-19
    • 2023-04-08
    • 2020-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多