让我说我有这样的事情:
var observable = observable1
.Merge(observable2)
.Merge(observable3);
var subscription = observable.Subscribe(ValueHandler);
...
public void ValueHandler(string nextValue)
{
Console.WriteLine($"Next value {nextValue} produced by /* sourceObservable */");
}
如果没有将该引用与每个可观察实现中的值一起添加,是否有一种方法可以从observable1
,observable2
和observable3
中获取源代码,从而生成下一个值?
答案 0 :(得分:2)
不,这与Merge
的设计完全相反。 Merge
旨在获取多个流并将其视为一个流。如果您想要某种方式单独处理它们,请使用不同的运算符。
对于传递源的操作员,简短的回答是否定的。 Rx是关于对消息的反应,来源是无关紧要的。我甚至不确定你是否可以在概念上定义Rx中的“来源”:
var observable1 = Observable.Interval(TimeSpan.FromSeconds(1)).Take(5);
var observable2 = observable1.Select(a => a.ToString());
var subscription = observable2.Subscribe(s => s.Dump());
订阅源observable1
,observable2
或某种指向系统时钟的指针?
如果您要将输入的邮件分开,那么您可以使用Select
,如下所示:
var observable = observable1.Select(o => Tuple.Create("observable1", o))
.Merge(observable2.Select(o => Tuple.Create("observable2", o)))
.Merge(observable3.Select(o => Tuple.Create("observable3", o)));
如果这太乱了,那么你可以轻松地制作一个扩展方法来清理它。
我还要补充一点,你在答案中发布的代码不是很像Rx。一般准则是避免直接实施IObservable
。 School
可以更简洁地重写如下:
public class School
{
//private Subject<Student> _subject = null;
private readonly ISubject<Student> _applicationStream = null;
public static readonly int MaximumNumberOfSeats = 100;
public string Name { get; set; }
public School(string name)
: this(name, new Subject<Student>())
{
}
public School(string name, ISubject<Student> applicationStream )
{
Name = name;
_applicationStream = applicationStream;
}
public void AdmitStudent(Student s)
{
_applicationStream.OnNext(s);
}
public IObservable<Student> ApplicationStream()
{
return _applicationStream;
}
public IObservable<Student> AcceptedStream()
{
return _applicationStream
.SelectMany(s => s != null ? Observable.Return(s) : Observable.Throw<Student>(new ArgumentNullException("student")))
.Distinct()
.Take(MaximumNumberOfSeats);
}
}
通过这种方式,您可以订阅所有应用程序,接受,如果您愿意,还可以订阅拒绝等等。您的状态也较少(无List<Student>
),理想情况下您甚至可以删除{{ 1}}并将其转换为在某处传递的Observable。
答案 1 :(得分:0)
不,没有任何开箱即用的信息可以为我们提供有关哪个observable产生价值的信息。
那是因为这是一个实现细节。
如果Rx的设计者必须提供这些附加信息,他们只能通过对TSource
泛型类型参数施加某种限制来实现。这不会很好。这是值处理程序可以知道谁生成了值的唯一方法。
因此,获取此信息的责任在于使用Rx实现开发人员。
为了举一个例子,让我们说你有一个School
课程,这是一个可以观察到这样的学生:
using System;
using System.Collections.Generic;
using System.Reactive.Subjects;
namespace SchoolManagementSystem
{
public class Student
{
public Student(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class School : IObservable<Student>
{
private List<Student> _students;
private Subject<Student> _subject = null;
public static readonly int MaximumNumberOfSeats = 100;
public string Name { get; set; }
public School(string name)
{
Name = name;
_students = new List<Student>();
_subject = new Subject<Student>();
}
public void AdmitStudent(Student student)
{
if (student == null)
{
var ex = new ArgumentNullException("student");
_subject.OnError(ex);
throw ex;
}
try
{
if (_students.Count == MaximumNumberOfSeats)
{
_subject.OnCompleted();
return;
}
if (!_students.Contains(student))
{
_students.Add(student);
_subject.OnNext(student);
}
}
catch(Exception ex)
{
_subject.OnError(ex);
}
}
public IDisposable Subscribe(IObserver<Student> observer)
{
return _subject.Subscribe(observer);
}
}
}
客户端代码如下:
using SchoolManagementSystem;
using System;
using System.Reactive.Linq;
namespace Client
{
class Program
{
static void Main(string[] args)
{
var school1 = new School("School 1");
var school2 = new School("School 2");
var school3 = new School("School 3");
var observable = school1
.Merge(school2)
.Merge(school3);
var subscription = observable
.Subscribe(PrintStudentAdmittedMessage, PrintNoMoreStudentsCanBeAdmittedMessage);
school1.FillWithStudents(100);
school2.FillWithStudents(102);
school3.FillWithStudents(101);
Console.WriteLine("Press any key to stop observing and to exit the program.");
Console.ReadKey();
subscription.Dispose();
}
static void PrintStudentAdmittedMessage(Student student)
{
Console.WriteLine($"Student admitted: {student}");
}
static void PrintNoMoreStudentsCanBeAdmittedMessage()
{
Console.WriteLine("No more students can be admitted.");
}
}
}
然后,要让客户知道学生入学的哪所学校,您必须更改TSource
的{{1}}类型。在这种情况下,您必须更改IObservable<TSource>
为School
的事实。
然而,改变这与域模型的语义相违背。因此,解决这个问题的方法是在学生内部包含对IObservable<Student>
的引用,如下所示:
School
然后你会改变using System;
using System.Collections.Generic;
namespace SchoolManagementSystem
{
public class Student
{
public Student(string name)
{
Name = name;
}
// Add this new property so you get this information
// in the value handler
public School School { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format($"({School.Name}: {Name})");
}
}
}
课程的AdmitStudent
方法,以表明学生被录取的学校,如下:
School