不,没有任何开箱即用的东西可以为我们提供有关哪个 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.");
}
}
}
那么,为了让客户知道一个学生被哪个学校录取,你必须改变IObservable<TSource>的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})");
}
}
}
然后您将更改 School 类的 AdmitStudent 方法以指示学生被录取的学校,如下所示:
public void AdmitStudent(Student student)
{
try
{
if (_students.Count == MaximumNumberOfSeats)
{
...
}
if (!_students.Contains(student))
{
// Add this line to indicate which school
// the student is being admitted to
student.School = this;
_students.Add(student);
_subject.OnNext(student);
}
}
catch(Exception ex)
{
_subject.OnError(ex);
}
}