我有一个很长的循环过程:
public void Process()
{
bool done = false;
do {
//do stuff
}while (!done);
}
我想切入比特并让调用例程在某种UI中显示我的进度。它是一个类库,因此调用者可能是任何东西(Console App,WinForms,WebApp,......)。
如果能做的话,这将是最简单的:
public void Process()
{
bool done = false;
do {
//do stuff
yield return;
}while (!done);
}
因此调用者可以继续调用该方法,直到完成为止。
这更像是BackgroundWorker的工作,但对于控制台应用程序而言似乎“错误”......我不会总是需要多线程。或者是吗?我的意思是,是的,我可以让控制台的主线程等待它完成。
我的问题是:我可以使用“收益回报”的“零碎”延迟执行功能而不实际返回某些内容吗?
答案 0 :(得分:12)
您想要的语言功能称为 coroutine (或者更准确地说,是 semicoroutine ,但我们不要迂腐。)C#迭代器块是一种弱形式的协程。我建议不要因为你想要协程而制作“虚拟”序列。
C#5中的await
运算符也是协程的一种形式,可能更接近您所需的解决方案,特别是如果您的操作在逻辑上是异步,高延迟操作。 C#5中有异步协同进程报告的标准模式;我会先阅读这篇文章:
答案 1 :(得分:11)
简而言之,不。
yield return
必须返回一些内容。
http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
Process
方法的返回类型应为IEnumerable
,IEnumerable<T>
,IEnumerator
或IEnumerator<T>
。如果您真的想使用objects
,则可以返回虚拟yield
。
您可能希望调查向调用者报告进度的不同方法。
答案 2 :(得分:9)
正如其他人已经回答的那样,不是没有办法,但为什么不简单地使用回调Func
或Action
或其他东西让被叫者与你的循环互动?< / p>
public void Process(Action callback)
{
bool done = false;
do {
//do stuff
callback();
}while (!done);
}
或使用其他类型的事件处理,通常用于此类事件。
答案 3 :(得分:6)
您说您希望调用者响应方法的进度。您可以返回进度信息:
class ProgressInfo { ... }
...
yield return new ProgressInfo() { ... };
然后,调用者将foreach
对结果进行操作并对其进行操作。
这比调用者检查全局可变状态要好得多。这是一个功能性解决方案。
答案 4 :(得分:3)
不,不可能。只有当返回类型为IEnumerable
或IEnumerator
时,编译器才会为您生成迭代器。
解决方法是返回一些值并更改方法的返回类型以使编译器满意。