Если я что-то упустил, вы не можете делать то, что просите.
(у меня есть ответ для вас, поэтому, пожалуйста, прочитайте мое объяснение, почему вы не можете сделать то, чтовы делаете сначала, а потом читаете дальше.)
Ваш полный метод будет выглядеть примерно так:
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);
}
};
}
Если мы предположим, что ваш код был "легальным", то когда GetSomeValues
вызывается, даже если обработчик DoWork
добавлен к worker
, лямбда-выражение не выполняется до тех пор, пока не сработает событие 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)
{
// process each er
}
});
Если вы знаете, что 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 =>
{
// process each 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, как «планировать» обработку подписок для наблюдателя.
Надеюсь, это поможет.