使用直接方法创建可观察对象
Create observables using straight methods
我需要重新收集一些调用方法的数据正在连接到网络服务。
问题: 假设我需要根据远程收集的信息更新标签控件的内容文本。在重新收集所有这些数据之前,我无法展示标签。
desired: 我想首先显示带有默认文本的标签,当我收到此信息时,我想更新标签内容(请不要不要把这个描述当成烂代码,我只是简单介绍一下我的真实情况)。
我想创建这些方法的可观察序列。然而,这些方法没有相同的签名。例如:
int GetInt() {
return service.GetInt();
}
string GetString() {
return service.GetString();
}
string GetString2 {
return service.GetString2();
}
这些方法不是async
。
是否可以创建这些方法的可观察序列?
如何创建它?
然而,实现我的目标的最佳选择是什么?
可以使用 Observable.Create 实现创建自定义可观察序列。使用您的要求的示例如下所示:
private int GetInt()
{
Thread.Sleep(1000);
return 1;
}
private string GetString()
{
Thread.Sleep(1000);
return "Hello";
}
private string GetString2()
{
Thread.Sleep(2000);
return "World!";
}
private IObservable<string> RetrieveContent()
{
return Observable.Create<string>(
observer =>
{
observer.OnNext("Default Text");
int value = GetInt();
observer.OnNext($"Got value {value}. Getting string...");
string string1 = GetString();
observer.OnNext($"Got string {string1}. Getting second string...");
string string2 = GetString2();
observer.OnNext(string2);
observer.OnCompleted();
return Disposable.Empty;
}
);
}
请注意我是如何通过在每个 GetXXX 方法中引入 Thread.Sleep
调用来模拟网络延迟的。为了确保你的 UI 在订阅这个 observable 时不会挂起,你应该按如下方式订阅:
IDisposable subscription = RetrieveContent()
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(text => Label = text);
此代码使用 .SubscribeOn(TaskPoolScheduler.Default)
扩展方法来使用 TaskPool 线程启动可观察序列,并且会被 Thread.Sleep 调用阻塞,但是,因为这不是 UI 线程,您的 UI 将保持响应。然后,为了确保我们在 UI 线程上更新 UI,我们使用“.ObserveOn(DispatcherScheduler.Current)”在设置(数据绑定)Label
属性.
希望这就是您要找的东西,如果不是,请发表评论,我会尽力提供进一步帮助。
我会考虑为您的服务创建包装器 class 以将值公开为单独的可观察值。
所以,从服务接口开始:
public interface IService
{
int GetInt();
string GetString();
string GetString2();
}
...然后你写 ServiceWrapper
:
public class ServiceWrapper : IService
{
private IService service;
private Subject<int> subjectGetInt = new Subject<int>();
private Subject<string> subjectGetString = new Subject<string>();
private Subject<string> subjectGetString2 = new Subject<string>();
public ServiceWrapper(IService service)
{
this.service = service;
}
public int GetInt()
{
var value = service.GetInt();
this.subjectGetInt.OnNext(value);
return value;
}
public IObservable<int> GetInts()
{
return this.subjectGetInt.AsObservable();
}
public string GetString()
{
var value = service.GetString();
this.subjectGetString.OnNext(value);
return value;
}
public IObservable<string> GetStrings()
{
return this.subjectGetString.AsObservable();
}
public string GetString2()
{
var value = service.GetString2();
this.subjectGetString2.OnNext(value);
return value;
}
public IObservable<string> GetString2s()
{
return this.subjectGetString2.AsObservable();
}
}
现在,假设您当前的服务称为 Service
,您将编写此代码来进行设置:
IService service = new Service();
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService`
var subscription =
Observable
.Merge(
wrapped.GetInts().Select(x => x.ToString()),
wrapped.GetStrings(),
wrapped.GetString2s())
.Subscribe(x => label.Text = x);
IService wrappedService = wrapped;
现在将 wrappedService
而不是 service
传递给您的代码。它仍在调用底层 service
代码,因此不需要 re-write,但您仍然可以获得所需的可观察值。
这实际上是四人组 decorator pattern。
我需要重新收集一些调用方法的数据正在连接到网络服务。
问题: 假设我需要根据远程收集的信息更新标签控件的内容文本。在重新收集所有这些数据之前,我无法展示标签。
desired: 我想首先显示带有默认文本的标签,当我收到此信息时,我想更新标签内容(请不要不要把这个描述当成烂代码,我只是简单介绍一下我的真实情况)。
我想创建这些方法的可观察序列。然而,这些方法没有相同的签名。例如:
int GetInt() {
return service.GetInt();
}
string GetString() {
return service.GetString();
}
string GetString2 {
return service.GetString2();
}
这些方法不是async
。
是否可以创建这些方法的可观察序列?
如何创建它?
然而,实现我的目标的最佳选择是什么?
可以使用 Observable.Create 实现创建自定义可观察序列。使用您的要求的示例如下所示:
private int GetInt()
{
Thread.Sleep(1000);
return 1;
}
private string GetString()
{
Thread.Sleep(1000);
return "Hello";
}
private string GetString2()
{
Thread.Sleep(2000);
return "World!";
}
private IObservable<string> RetrieveContent()
{
return Observable.Create<string>(
observer =>
{
observer.OnNext("Default Text");
int value = GetInt();
observer.OnNext($"Got value {value}. Getting string...");
string string1 = GetString();
observer.OnNext($"Got string {string1}. Getting second string...");
string string2 = GetString2();
observer.OnNext(string2);
observer.OnCompleted();
return Disposable.Empty;
}
);
}
请注意我是如何通过在每个 GetXXX 方法中引入 Thread.Sleep
调用来模拟网络延迟的。为了确保你的 UI 在订阅这个 observable 时不会挂起,你应该按如下方式订阅:
IDisposable subscription = RetrieveContent()
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(text => Label = text);
此代码使用 .SubscribeOn(TaskPoolScheduler.Default)
扩展方法来使用 TaskPool 线程启动可观察序列,并且会被 Thread.Sleep 调用阻塞,但是,因为这不是 UI 线程,您的 UI 将保持响应。然后,为了确保我们在 UI 线程上更新 UI,我们使用“.ObserveOn(DispatcherScheduler.Current)”在设置(数据绑定)Label
属性.
希望这就是您要找的东西,如果不是,请发表评论,我会尽力提供进一步帮助。
我会考虑为您的服务创建包装器 class 以将值公开为单独的可观察值。
所以,从服务接口开始:
public interface IService
{
int GetInt();
string GetString();
string GetString2();
}
...然后你写 ServiceWrapper
:
public class ServiceWrapper : IService
{
private IService service;
private Subject<int> subjectGetInt = new Subject<int>();
private Subject<string> subjectGetString = new Subject<string>();
private Subject<string> subjectGetString2 = new Subject<string>();
public ServiceWrapper(IService service)
{
this.service = service;
}
public int GetInt()
{
var value = service.GetInt();
this.subjectGetInt.OnNext(value);
return value;
}
public IObservable<int> GetInts()
{
return this.subjectGetInt.AsObservable();
}
public string GetString()
{
var value = service.GetString();
this.subjectGetString.OnNext(value);
return value;
}
public IObservable<string> GetStrings()
{
return this.subjectGetString.AsObservable();
}
public string GetString2()
{
var value = service.GetString2();
this.subjectGetString2.OnNext(value);
return value;
}
public IObservable<string> GetString2s()
{
return this.subjectGetString2.AsObservable();
}
}
现在,假设您当前的服务称为 Service
,您将编写此代码来进行设置:
IService service = new Service();
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService`
var subscription =
Observable
.Merge(
wrapped.GetInts().Select(x => x.ToString()),
wrapped.GetStrings(),
wrapped.GetString2s())
.Subscribe(x => label.Text = x);
IService wrappedService = wrapped;
现在将 wrappedService
而不是 service
传递给您的代码。它仍在调用底层 service
代码,因此不需要 re-write,但您仍然可以获得所需的可观察值。
这实际上是四人组 decorator pattern。