C# 试图理解SelectMany的这种用法

C# 试图理解SelectMany的这种用法,c#,system.reactive,C#,System.reactive,我对SelectMany的使用有几个问题,我在我正在从事的一个项目中遇到了很多问题。下面是一个小示例,它再现了它的用法(我使用了一些Console.writeline来帮助查看各个点的状态): 公共部分类主窗口:INotifyPropertyChanged { 私人住宅区1、2、3、4; private readonly ISubject_cb1HasChanged=新主题(); private readonly issubject_cb2HasChanged=新主题(); private re

我对SelectMany的使用有几个问题,我在我正在从事的一个项目中遇到了很多问题。下面是一个小示例,它再现了它的用法(我使用了一些Console.writeline来帮助查看各个点的状态):

公共部分类主窗口:INotifyPropertyChanged
{
私人住宅区1、2、3、4;
private readonly ISubject_cb1HasChanged=新主题();
private readonly issubject_cb2HasChanged=新主题();
private readonly issubject_cb3HasChanged=new Subject();
private readonly ISubject _initialState=new ReplaySubject(1);
公共主窗口()
{
初始化组件();
DataContext=this;
observecheckbox();
var initialState=string.Format(“{0}{1}{2}”,CB1、CB2、CB3);
_initialState.OnNext(initialState);
Console.WriteLine(“初始状态:“+initialState”);
}
公共图书馆CB1
{
得到
{
返回cb1;
}
设置
{
_cb1=数值;
_cb1HasChanged.OnNext(单位默认值);
}
}
公共图书馆CB2
{
得到
{
返回cb2;
}
设置
{
_cb2=数值;
_cb2HasChanged.OnNext(单位默认值);
}
}
公共图书馆CB3
{
得到
{
返回cb3;
}
设置
{
_cb3=数值;
_cb3HasChanged.OnNext(单位默认值);
}
}
公共图书馆
{
得到
{
返回(u isDirty);;
}
设置
{
_isDirty=值;
不动产变更(“IsDirty”);
}
}
私有void observecheckbox()
{
var checkBoxChanges=new[]
{
_CB1发生了变化,
_CB2发生了变化,
_Cb3改变
}
.Merge();
var isDirty=\u initialState.SelectMany(initialState=>checkBoxChanges
.Select(=>GetNewState(initialState))
.选择(updatedState=>initialState!=updatedState)
.StartWith(假)
.TakeUntil(_initialState.Skip(1));
订阅(d=>isDirty=d);
}
私有字符串GetNewState(字符串initialState=null)
{
字符串更新=string.Format(“{0}{1}{2}”,CB1,CB2,CB3);
if(initialState!=null)
{
Console.WriteLine(“创建更新:+UPDATE+”初始状态:+initialState”);
}
其他的
{
Console.WriteLine(“创建更新:+UPDATE”);
}
返回更新;
}
公共事件属性更改事件处理程序属性更改;
void OnPropertyChanged(字符串属性)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(prop));
}
}
私有无效按钮\u单击(对象发送者,System.Windows.RoutedEventArgs e)
{
var newState=GetNewState();
_initialState.OnNext(新闻状态);
Console.WriteLine(“另存为:“+newState”);
}
}
以及xaml:

<Window x:Class="WpfSB2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <CheckBox IsChecked="{Binding CB1}"></CheckBox>
            <CheckBox IsChecked="{Binding CB2}"></CheckBox>
            <CheckBox IsChecked="{Binding CB3}"></CheckBox>
            <Button IsEnabled="{Binding IsDirty}" Click="Button_Click">APPLY</Button>
        </StackPanel>
    </Grid>
</Window>

申请
因此,这个小应用程序所做的就是显示三个复选框(最初都未选中)和一个“应用”按钮。当复选框的状态更改时,按钮应变为启用状态,单击时变为禁用状态,直到复选框的状态再次更改。如果更改复选框的状态,然后将其更改回初始状态,则按钮将相应地启用/禁用。该应用程序按预期运行,我只是想弄清楚为什么/如何运行

现在问题是:

  • 每当_initialState或复选框发生更改时,是否会触发SelectMany调用

  • 第一次调用_initialState.OnNext(initialState);(在构造函数中)在涉及SelectMany代码时实际上没有做任何事情。我看到它进入SelectMany代码,但实际上什么也没做(我的意思是,如果我在复选框Changes上设置断点。SelectSection它会中断,但实际上什么也没被选中)。这是因为任何复选框尚未发生更改吗

  • 正如预期的那样,选中任何复选框都会触发isDirty检查。第一次更改单个复选框时,此SelectMany语句中到底发生了什么

  • 选中一个框后,应用按钮被启用,我点击应用。这将导致_initialState.OnNext(newState);被称为。与我的第一个问题类似,SelectMany语句中似乎没有发生任何事情。我原以为初始状态获得一个新值时,会重新计算某些内容,但它似乎直接进入isDirty.Subscribe的OnNext处理程序(d=>isDirty=d)

  • 现在我点击Apply,_initialState.OnNext总共被调用了两次。如果我选中一个新复选框,SelectMany如何处理?它经历了过去所有的州吗?在处理可观测数据之前,这些值是否已存储

  • 开始/结束/跳过行在做什么?我注意到,如果我删除TakeUntil行,当SelectMany子句开始遍历_initialState的所有过去值时,应用程序将停止正常工作,并且会混淆要比较的实际当前状态


如果您需要更多信息,请告诉我。

我认为您问题的关键在于您对SelectMany的理解。我认为,如果您将SelectMany称为“从一个选择多个”,则更容易理解

对于源序列中的每个值,选择many wil
<Window x:Class="WpfSB2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <CheckBox IsChecked="{Binding CB1}"></CheckBox>
            <CheckBox IsChecked="{Binding CB2}"></CheckBox>
            <CheckBox IsChecked="{Binding CB3}"></CheckBox>
            <Button IsEnabled="{Binding IsDirty}" Click="Button_Click">APPLY</Button>
        </StackPanel>
    </Grid>
</Window>