Joa*_*nge 31 .net c# anonymous-methods backgroundworker yield-return
基本上我有一个匿名的方法,我用于我的BackgroundWorker:
worker.DoWork += ( sender, e ) =>
{
foreach ( var effect in GlobalGraph.Effects )
{
// Returns EffectResult
yield return image.Apply (effect);
}
};
Run Code Online (Sandbox Code Playgroud)
当我这样做时,编译器告诉我:
"yield语句不能在匿名方法或lambda表达式中使用"
那么在这种情况下,最优雅的方法是什么?顺便说一句,这个DoWork方法在静态方法中,以防对解决方案很重要.
ang*_*son 16
不幸的是你不能.
编译器不允许您组合两个"神奇"的代码片段.两者都涉及重写代码以支持您要执行的操作:
但是,您可以重写代码以返回集合,因此在您的特定情况下,我会这样做:
worker.DoWork += ( sender, e ) =>
{
return GlobalGraph.Effects
.Select(effect => image.Apply(effect));
};
Run Code Online (Sandbox Code Playgroud)
虽然事件看起来很奇怪但根本(sender, e)不会返回任何东西.你确定你为我们展示了一个真实的场景吗?
编辑好的,我想我看到你在这里想做什么.
您有一个静态方法调用,然后您想在后台执行代码,然后在后台调用完成后从该静态方法返回数据.
这虽然可能不是一个好的解决方案,因为你有效地暂停一个线程等待另一个线程,这是在你暂停线程之前直接启动的.换句话说,您所做的只是增加上下文切换的开销.
相反,您需要开始后台工作,然后在完成该工作后,处理结果数据.
Tej*_*ejs 10
也许只返回linq表达式并延迟执行如yield:
return GlobalGraph.Effects.Select(x => image.Apply(x));
Run Code Online (Sandbox Code Playgroud)
除非我遗漏了什么,否则你不能做你所要求的.
(我的确有一个答案,所以请仔细阅读我的解释,说明为什么你不能先做你正在做的事情,然后继续阅读.)
你完整的方法看起来像这样:
public static IEnumerable<EffectResult> GetSomeValues()
{
// code to set up worker etc
worker.DoWork += ( sender, e ) =>
{
foreach ( var effect in GlobalGraph.Effects )
{
// Returns EffectResult
yield return image.Apply (effect);
}
};
}
Run Code Online (Sandbox Code Playgroud)
如果我们假设您的代码是"合法的"那么在GetSomeValues调用时,即使DoWork添加了处理程序worker,在DoWork触发事件之前不会执行lambda表达式.因此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)
);
}
Run Code Online (Sandbox Code Playgroud)
现在你的GetSomeValues方法的调用者会这样做:
GetSomeValues().Subscribe(ers =>
{
foreach (var er in ers)
{
// process each er
}
});
Run Code Online (Sandbox Code Playgroud)
如果你知道这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();
}
Run Code Online (Sandbox Code Playgroud)
这段代码看起来有点复杂,但它只是将单个do work事件转换为EffectResult对象流.
然后调用代码如下所示:
GetSomeValues().Subscribe(er =>
{
// process each er
});
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
调用代码与前一个示例相同.该Scheduler.ThreadPool告诉的Rx如何"安排"订阅观察者的处理.
我希望这有帮助.
好吧,我做了这样的事情,它做了我想要的事情(省略了一些变量):
public static void Run ( Action<float, EffectResult> action )
{
worker.DoWork += ( sender, e ) =>
{
foreach ( var effect in GlobalGraph.Effects )
{
var result = image.Apply (effect);
action (100 * ( index / count ), result );
}
}
};
Run Code Online (Sandbox Code Playgroud)
然后在调用站点中:
GlobalGraph.Run ( ( p, r ) =>
{
this.Progress = p;
this.EffectResults.Add ( r );
} );
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13834 次 |
| 最近记录: |