SelectMany触发订阅,而选择不

发布于 2025-02-12 00:52:05 字数 3568 浏览 0 评论 0原文

在下面的示例中,我不明白为什么选择在SelectMany时不会触发订阅。这个示例是基于我正在研究的事情,但缩短为简单,使问题可再现。

当我点击按钮时,_subject.onnext被调用。 ViewModel订阅_subject和调用getObservable(),它返回iobservable< unit>。此时,debug.writeline(“订阅”);未在getObservable()中击中。

但是,如果我更改_subject.Select(_ => getObServable())。subsibribre(); _subject.SelectMany(_ => getObservable())。调试线被击中。

订阅如何使用SelectMany而不是选择?我的理解是,使用可观察到的。创建,在订阅时,指定的代表将被执行。我只是看不到SelectMany在哪里进行订阅。

查看:

<Window x:Class="Rxtest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:Rxtest"
        d:DataContext="{d:DesignInstance Type=viewModels:ViewModel}"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button Command="{Binding SaveCommand}"/>
    </Grid>
</Window>

背后的代码:

using System.Windows;

namespace Rxtest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }
}

ViewModel:

using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows.Input;

namespace Rxtest
{
    public class ViewModel
    {
        private ICommand _saveCommand;
        private Subject<int> _subject = new Subject<int>();

        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand(
                        p => true,
                        p => DoSomeImportantMethod());
                }
                return _saveCommand;
            }
        }

        public ViewModel()
        {
            _subject.Select(_ => GetObservable()).Subscribe();

        }        

        private void DoSomeImportantMethod()
        {
            _subject.OnNext(1);
        }

        private IObservable<Unit> GetObservable()
        {
            return Observable.Create<Unit>(observer =>
            {
                observer.OnNext(Unit.Default);
                Debug.WriteLine("SUBSCRIBED");
                return Disposable.Empty;
            });
        }
    }

    public class RelayCommand : ICommand
    {
        private readonly Predicate<object> _canExecute;
        private readonly Action<object> _execute;

        public RelayCommand(Predicate<object> canExecute, Action<object> execute)
        {
            _canExecute = canExecute;
            _execute = execute;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

I do not understand in the example below why Select does not trigger the subscription while SelectMany does. This example is based off of something I am working on but reduced to as simple as I can get it so that the issue is reproducible.

When I hit the button, _subject.OnNext is called. The ViewModel is subscribed to _subject and calls GetObservable() which returns an IObservable<Unit>. At this point Debug.WriteLine("SUBSCRIBED"); is not hit in GetObservable().

However, if I change _subject.Select(_ => GetObservable()).Subscribe(); to _subject.SelectMany(_ => GetObservable()).Subscribe(); the debug line is hit.

How is the subscription happening with SelectMany and not with Select? My understanding is that with Observable.Create, the specified delegate will be executed anytime a subscription is made. I just don't see where the subscription is being made with SelectMany.

View:

<Window x:Class="Rxtest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:Rxtest"
        d:DataContext="{d:DesignInstance Type=viewModels:ViewModel}"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button Command="{Binding SaveCommand}"/>
    </Grid>
</Window>

Code behind:

using System.Windows;

namespace Rxtest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }
}

ViewModel:

using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows.Input;

namespace Rxtest
{
    public class ViewModel
    {
        private ICommand _saveCommand;
        private Subject<int> _subject = new Subject<int>();

        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand(
                        p => true,
                        p => DoSomeImportantMethod());
                }
                return _saveCommand;
            }
        }

        public ViewModel()
        {
            _subject.Select(_ => GetObservable()).Subscribe();

        }        

        private void DoSomeImportantMethod()
        {
            _subject.OnNext(1);
        }

        private IObservable<Unit> GetObservable()
        {
            return Observable.Create<Unit>(observer =>
            {
                observer.OnNext(Unit.Default);
                Debug.WriteLine("SUBSCRIBED");
                return Disposable.Empty;
            });
        }
    }

    public class RelayCommand : ICommand
    {
        private readonly Predicate<object> _canExecute;
        private readonly Action<object> _execute;

        public RelayCommand(Predicate<object> canExecute, Action<object> execute)
        {
            _canExecute = canExecute;
            _execute = execute;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七秒鱼° 2025-02-19 00:52:05

全部都在打字中。 .select在这里返回双重观察,iObservable&lt; iobservable&lt; unit&gt;&gt;。订阅呼叫订阅可观察到的外部,但您的调试语句仅存在于内部观察处。内部可观察的仍然没有订阅。

.selectmany将双重观察的可观察到一个简单的iObservable&lt; unit&gt;在其中您的调试语句将发射。

It’s all in the typing. .Select here is returning a double observable, IObservable<IObservable<Unit>>. The subscribe call subscribes to the outer observable, but your Debug statement only exists on the inner observable. The inner observable remains unsubscribed to.

.SelectMany flattens the double observable into a simple IObservable<Unit> where your Debug statement will fire.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文