除非我漏掉了什么,否则你无法做到你所要求的。
(我有一个答案可以回答你,请先阅读我解释为什么你不能做你正在做的事情,然后继续阅读。)
你的完整方法应该像这样:
public static IEnumerable<EffectResult> GetSomeValues()
{
worker.DoWork += ( sender, e ) =>
{
foreach ( var effect in GlobalGraph.Effects )
{
yield return image.Apply (effect);
}
};
}
如果我们假设您的代码是“合法”的,那么当调用
GetSomeValues
时,即使将
DoWork
处理程序添加到
worker
中,lambda表达式也不会在
DoWork
事件触发之前执行。因此,对
GetSomeValues
的调用完成后没有返回任何结果,lamdba可能会在以后的某个阶段被调用-这对于
GetSomeValues
方法的调用者来说已经太晚了。
最好的答案是使用
Rx。
Rx颠覆了
IEnumerable<T>
的方式。Rx不是从可枚举对象中请求值,而是从
IObservable<T>
中推送值给你。
由于您正在使用后台工作器并响应事件,因此实际上已经将值推送给您。使用Rx可以轻松地完成您要尝试的操作。
您有几个选项。可能最简单的方法是这样做:
public static IObservable<IEnumerable<EffectResult>> GetSomeValues()
{
// code to set up worker etc
return from e in Observable.FromEvent<DoWorkEventArgs>(worker, "DoWork")
select (
from effect in GlobalGraph.Effects
select image.Apply(effect)
);
}
现在,您的
GetSomeValues
方法的调用者将会这样做:
GetSomeValues().Subscribe(ers =>
{
foreach (var er in ers)
{
}
});
如果你知道DoWork
只会被触发一次,那么这种方式可能会更好:
public static IObservable<EffectResult> GetSomeValues()
{
// code to set up worker etc
return Observable
.FromEvent<DoWorkEventArgs>(worker, "DoWork")
.Take(1)
.Select(effect => from effect in GlobalGraph.Effects.ToObservable()
select image.Apply(effect))
.Switch();
}
这段代码看起来有点复杂,但它只是将单个“do work”事件转换为一系列EffectResult
对象。
然后调用代码如下:
GetSomeValues().Subscribe(er =>
{
});
Rx甚至可以用来替代后台工作线程。这可能是您的最佳选择:
public static IObservable<EffectResult> GetSomeValues()
{
// set up code etc
return Observable
.Start(() => from effect in GlobalGraph.Effects.ToObservable()
select image.Apply(effect), Scheduler.ThreadPool)
.Switch();
}
调用代码与之前的示例相同。 Scheduler.ThreadPool
告诉 Rx 如何 "调度" 处理对观察者的订阅。
希望这可以帮到你。