.net 编写可用和可维护的代码
我是反应式编程新手,遇到了一个问题 我的代码如下所示:.net 编写可用和可维护的代码,.net,system.reactive,reactive-programming,.net,System.reactive,Reactive Programming,我是反应式编程新手,遇到了一个问题 我的代码如下所示: IsBusy = true; service.BeginGetClients(param, c => { var r = service.EndGetClients(c); if(!CheckResult(r)) { service.BeginGetCachedClients(param, c2 =>
IsBusy = true;
service.BeginGetClients(param, c =>
{
var r = service.EndGetClients(c);
if(!CheckResult(r))
{
service.BeginGetCachedClients(param, c2 =>
{
var r2 = service.EndGetCachedClients(c2);
if(CheckResult(r2))
ShowMessage("clients valid");
else
ShowMessage("clients not valid");
UpdateClients(r2);
service.BeginUpdateClients(r2, c3 =>
{
var b = service.EndUpdateClients(c3);
if(b)
ShowMessage("clients updated");
else
ShowMessage("clients not updated");
IsBusy = false;
}, null);
}, null);
}
else
{
ShowMessage("error on get clients");
IsBusy = false;
}
}, null);
如何更改为fluent Rx?我从以下代码开始:
var invokeClients = Observable.FromAsyncPattern<Param, List<Client>>(service.BeginGetClients, service.EndGetClients);
var invokeCachedClients = Observable.FromAsyncPattern<Param, List<Client>>(service.BeginGetCachedClients, service.EndGetCachedClients);
invokeClients(param)
.Subscribe(r =>
{
if(!CheckResult(r))
{
invokeCachedClients(param)
.Subscribe(r2 =>
{
// TODO: next op
});
}
});
var invokeClients=Observable.FromAsyncPattern(service.BeginGetClients,service.EndGetClients);
var invokeCachedClient=Observable.FromAsyncPattern(service.beginGetCachedClient,service.endGetCachedClient);
调用客户端(参数)
.订阅(r=>
{
如果(!检查结果(r))
{
InvokeCachedClient(参数)
.订阅(r2=>
{
//TODO:下一次行动
});
}
});
有什么改进代码的建议吗?也许还有别的解决办法?
我不喜欢这个级联代码
谢谢
invokeClients(param)
.Where(x => !CheckResult(x))
.Select(invokeCachedClients)
.Do(_ => IsBusy = true)
.Merge()
.Do(_ => IsBusy = false)
.Subscribe(x => Console.WriteLine("Do something here"));
确保订阅,否则它将不起作用(这就像不进行LINQ查询)像这样的事情,你总是想彻底改变。转换这一点最困难的部分是异步调用之间的部分。如果您将一个右键的结果输入到下一个右键,那么它将是从async1中的x()到async2(x)中的y的直接
。
。我看到了两个功能,可以将其分解为:
public IObserservable<string> UpdateCachedClients(object param)
{
var getCachedClientsAsync = Observable.FromAsyncPattern<...>(service.BeginGetCachedClients, service.EndGetCachedClients);
var updateClientsAsync = Observable.FromAsyncPattern<...>(service.BeginUpdateClients, service.EndUpdateClients);
return Observable.Create<string>(obs =>
{
return (from r2 in getCachedClientsAsync(param)
.Do(v =>
{ if (CheckResult(v))
obs.OnNext("clients valid");
else
obs.OnNext("clients not valid");
//huh? is this done twice
UpdateClients(v);
})
from b in updateClientsAsync(r2)
select (b ? "clients updated" : "clients not updated")
).Subscribe(obs);
});
}
public IObservable<string> UpdateAllClients(object param)
{
var getClientsAsync = Observable.FromAsyncPattern<...>(service.BeginGetClients, service.EndGetClients);
return from r in getClientsAsync(param)
select (CheckResult(r) ?
Observable.Return("error on get clients") :
UpdateCachedClients(param));
}
请注意,我在OnError和OnCompleted中都将IsBusy
设置为false,因为这两个选项都是IObservable的终止消息
TPL似乎更适合这样的异步方法,因为它们只产生一个值,但在使用async/await的下一版本语言之前,如果您使用Tasks而不是IObservable,您可能会得到与您的方法或我的方法类似的语法。如上所述
invokeClients(param)
.Where(x => !CheckResult(x))
.SelectMany(invokeCachedClients)
.Subscribe(x => Console.WriteLine("Do something here"));
也可以写成
var query = from client in invokeClients(param)
where !CheckResult(client)
from cache in invokeCachedClients(client)
select cache;
然后,您可以将busy标志包装在资源中
Func<IDisposable> busyResource =
() =>
{
IsBusy = true;
return Disposable.Create(() => IsBusy = false);
};
您倾向于使用方法而不是将IsBusy setters置于OnError或OnCompleted中的原因是,如果订阅也被释放,这将停止它
我相信我们可能会做得更好,但我发现很难理解你到底在做什么。老实说,我认为这实际上比Rx更适合TPL或数据工作流,也就是说,您实际上是在链接工作连续性,而不是对一系列事件作出反应。谢谢,这对我帮助很大。但是如何中止第一次操作呢?不应调用“updateClientsAsync(r2)中的from b”。您将来更喜欢什么:异步/等待方法还是Rx?我也会添加IsBusy。
Func<IDisposable> busyResource =
() =>
{
IsBusy = true;
return Disposable.Create(() => IsBusy = false);
};
Observable.Using(busyResource, _=>query)
.Subscribe(x=>Console.Write("Do something here");