- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在编写重构 Silverlight 程序以使用 WCF 服务中的部分现有业务逻辑。这样做时,我遇到了 Silverlight 3 中的限制,它只允许对 WCF 服务进行异步调用,以避免长时间运行或无响应的服务调用阻塞 UI 线程的情况(SL 有一个有趣的队列模型来调用 WCF 服务在 UI 线程上)。
因此,编写曾经简单明了的内容正变得越来越复杂(请参阅问题末尾的代码示例)。
理想情况下,我会使用 coroutines为了简化实现,但遗憾的是,C# 目前不支持协程作为本地语言工具。但是,C# 确实有使用 yield return
的生成器(迭代器)的概念。句法。我的想法是重新调整 yield 关键字的用途,以允许我为相同的逻辑构建一个简单的协程模型。
但是,我不愿意这样做,因为我担心可能会有一些我没有预料到的隐藏(技术)陷阱(考虑到我对 Silverlight 和 WCF 的相对缺乏经验)。我还担心 future 的开发人员可能不清楚实现机制,并且可能会阻碍而不是简化他们 future 维护或扩展代码的工作。我在 SO 上看到了这个关于重新利用迭代器来构建状态机的问题:implementing a state machine using the "yield" keyword ,虽然这与我正在做的事情并不完全相同,但它确实让我停下来。
但是,我需要做一些事情来隐藏服务调用的复杂性,并管理此类更改中的工作量和潜在的缺陷风险。我对可以用来解决这个问题的其他想法或方法持开放态度。
代码的原始非 WCF 版本如下所示:
void Button_Clicked( object sender, EventArgs e ) {
using( var bizLogic = new BusinessLogicLayer() ) {
try {
var resultFoo = bizLogic.Foo();
// ... do something with resultFoo and the UI
var resultBar = bizLogic.Bar(resultFoo);
// ... do something with resultBar and the UI
var resultBaz = bizLogic.Baz(resultBar);
// ... do something with resultFoo, resultBar, resultBaz
}
}
}
重构后的 WCF 版本变得更加复杂(即使没有异常处理和前后条件测试):
// fields needed to manage distributed/async state
private FooResponse m_ResultFoo;
private BarResponse m_ResultBar;
private BazResponse m_ResultBaz;
private SomeServiceClient m_Service;
void Button_Clicked( object sender, EventArgs e ) {
this.IsEnabled = false; // disable the UI while processing async WECF call chain
m_Service = new SomeServiceClient();
m_Service.FooCompleted += OnFooCompleted;
m_Service.BeginFoo();
}
// called asynchronously by SL when service responds
void OnFooCompleted( FooResponse fr ) {
m_ResultFoo = fr.Response;
// do some UI processing with resultFoo
m_Service.BarCompleted += OnBarCompleted;
m_Service.BeginBar();
}
void OnBarCompleted( BarResponse br ) {
m_ResultBar = br.Response;
// do some processing with resultBar
m_Service.BazCompleted += OnBazCompleted;
m_Service.BeginBaz();
}
void OnBazCompleted( BazResponse bz ) {
m_ResultBaz = bz.Response;
// ... do some processing with Foo/Bar/Baz results
m_Service.Dispose();
}
上面的代码显然是一种简化,因为它省略了异常处理、无效性检查和生产代码中必需的其他做法。尽管如此,我认为它证明了 Silverlight 中的异步 WCF 编程模型开始出现复杂性的快速增加。重构原始实现(它没有使用服务层,而是将其逻辑嵌入到 SL 客户端中)很快就会成为一项艰巨的任务。并且很可能很容易出错。
代码的协程版本看起来像这样(我还没有测试过):
void Button_Clicked( object sender, EventArgs e ) {
PerformSteps( ButtonClickCoRoutine );
}
private IEnumerable<Action> ButtonClickCoRoutine() {
using( var service = new SomeServiceClient() ) {
FooResponse resultFoo;
BarResponse resultBar;
BazResponse resultBaz;
yield return () => {
service.FooCompleted = r => NextStep( r, out resultFoo );
service.BeginFoo();
};
yield return () => {
// do some UI stuff with resultFoo
service.BarCompleted = r => NextStep( r, out resultBar );
service.BeginBar();
};
yield return () => {
// do some UI stuff with resultBar
service.BazCompleted = r => NextStep( r, out resultBaz );
service.BeginBaz();
};
yield return () => {
// do some processing with resultFoo, resultBar, resultBaz
}
}
}
private void NextStep<T>( T result, out T store ) {
store = result;
PerformSteps(); // continues iterating steps
}
private IEnumerable<Action> m_StepsToPerform;
private void PerformSteps( IEnumerable<Action> steps ) {
m_StepsToPerform = steps;
PerformSteps();
}
private void PerformSteps() {
if( m_StepsToPerform == null )
return; // nothing to do
m_StepsToPerform.MoveNext();
var nextStep = m_StepsToPerform.Current;
if( nextStep == null ) {
m_StepsToPerform.Dispose();
m_StepsToPerform = null;
return; // end of steps
}
nextStep();
}
上面的代码有各种各样需要改进的地方。但基本前提是分解出延续模式(为异常处理和各种检查创建拦截点),同时允许 WCF 基于事件的异步模型在执行每个步骤时驱动 - 基本上是在最后一个异步 WCF 调用完成时。虽然从表面上看这看起来像是更多代码,但值得一提的是 PerformSteps()
和 NextStep()
是可重用的,只有在ButtonClickCoRoutine()
中实现会随着每个不同的实现站点而变化。
我不确定我是否喜欢这个模型,如果有更简单的方法来实现它,我也不会感到惊讶。但是我无法在“interwebs”或 MSDN 或其他任何地方找到一个。预先感谢您的帮助。
最佳答案
你绝对应该看看 Concurrency and Coordination Runtime .它使用迭代器正是为了这个目的。
另一方面,你也应该看看Parallel Extensions及其延续的方法。 Parallel Extensions 是 .NET 4.0 的一部分,而 CCR 需要单独的许可。不过,我会建议您使用由吃、呼吸和 sleep 这些东西的人编写的框架。自己很容易弄错细节。
关于c# - (错误)使用 C# 迭代器实现协程的陷阱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1903531/
正如问题所说,C++ 程序员在转向 Java 时面临哪些常见/主要问题?我正在寻找一些广泛的主题名称或示例以及工程师必须进行的日常调整。然后我可以去深入阅读这个。 我对多年来使用 C++ 并不得不使用
我们正在准备发布一个在过去一年中一直在开发的大型网络应用程序。我们即将开始集成 ActiveMerchant 的过程,以处理该服务的经常性订阅费用。 我正在寻找关于考虑到我们的要求(如下所列)的最佳实
您陷入过哪些 Powershell 陷阱? :-) 我的是: # ----------------------------------- function foo() { @("text")
对于商业数据库而言,数据库升级是一个优先级很高的事情,有版本升级路线图,有相应的补丁,而且对于方案还有一系列的演练,显然是一场硬仗。而在MySQL方向上,升级这件事情就被淡化了许多,好像只能证明它的
Android 新增了 AsyncLayoutInflater类到他们的支持库版本 24.0 和更高版本,并且可以在 Android SDK 4.0 或更高版本(几乎所有可用的设备)中使用。 根据 A
作为一名刚接触 Vala 的程序员,您对刚接触该语言的人的第一条建议是什么? 最佳答案 这很大程度上取决于您的背景。如果您来自 C/C++/Java,最好的建议是学习函数式编程。 Vala 支持真正的
作为 Spring 世界的新手,我认为如果有一个社区 Wiki 页面列出基于 Spring 的项目中常见的陷阱会很好。 这些包括: 被误解的概念 在 Spring 3.X 中不再推荐的 Spring
我正在开发一个脚本来管理一些陷阱。一开始我只用这段代码管理 INT 和 SIGTSTP,它工作得很好: #!/bin/bash function capture_traps() { echo
bash 中是否可以在函数退出时调用某些命令。我的意思是: function foo { # something like this maybe? trap "echo \"exit
我们在我们的域中托管了一个应用程序。所有用户都需要先通过 POST 表单登录。登录后,表单会自动重定向到我们网站上的仪表板页面。 是否可以允许一些客户托管他们自己的登录表单(在他们的网站上),然后发布
我有一个无窗口计时器(没有 WM_TIMER),它只在给定的时间段过去后触发一次回调函数。它作为 SetTimer()/KillTimer() 实现。时间段足够小:100-300 毫秒。 对于每个如此
我使用 Java 大约一个月了,总体而言仍然是编程方面的业余爱好者,所以如果我有什么不对的地方,请随时纠正我。也许我会提供一些多余的细节,但我现在很困惑,无法决定什么才是重要的。 因此,我一直在开发多
我正在开发一个需要使用 FileSystemWatcher 类的 C# 程序,以便在创建新文件时通知它。作为初始化的一部分,程序会扫描目录,以便处理其中已存在的任何文件。一切正常。 但是,在与另一位开
下面材料整理自Internet&著作。 STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list
我正在使用 NuGet 包 Polly实现捕获故障转移 SQL 异常的重试逻辑。我在 Azure 中设置了 SQL Server Always On 高可用性。 我不想捕获所有 SQL 异常(这是不正
在编写 Scala RemoteActor 代码时,我注意到了一些陷阱: 必须设置 RemoteActor.classLoader = getClass().getClassLoader() 以避免“
出于某种原因,当我针对不存在的文件运行以下脚本时,我的脚本没有捕获异常。我基于我在网上找到的示例中的代码,但它似乎对我不起作用。 我将不胜感激有关如何解决此问题的任何提示或指示。 注意:在下面的例子中
我正在尝试从 R 调用 winBUGS 来估计逻辑回归。我正在使用以下代码: # Directorio de trabajo setwd("~/3 Diplomado/7 Bayesiana/8t1"
我正在尝试从 R 调用 winBUGS 来估计逻辑回归。我正在使用以下代码: # Directorio de trabajo setwd("~/3 Diplomado/7 Bayesiana/8t1"
我正在使用 ctypes 包装一个大型 C 库。 ctypesgen生成了包装代码(与我自己的做法相差不远)。作为包装 C 结构的 ctypes 的一部分,它们被制作为对象,其中一些在 C 中具有“s
我是一名优秀的程序员,十分优秀!