Как активировать другой Enumerator внутри первого

У меня есть два отдельных действия, которые являются перечислителями.

Один можно запустить независимо, другой зависит от первого, который будет запущен позже.

Я думал, что я был бы очень умным, если бы сделал это:

public IEnumerator<IResult> DoStuffIndependently()
{
   yield return this;
   yield return that;
}

public IEnumerator<IResult> DoStuffBeforeSometimes()
{
   yield return AffectThis;
   yield return AffectThat;

   yield return DoStuffIndependently();
}

Это не работает, также не работает передача через foreach. Я не хочу проходить через все сам, и я предполагаю, что есть очень простой способ сделать это.


person Ingó Vals    schedule 18.07.2012    source источник
comment
Почему установка через foreach не работает?   -  person Dan Puzey    schedule 18.07.2012
comment
Есть ли конкретная причина для IEnumerator вместо IEnumerable?   -  person Branko Dimitrijevic    schedule 18.07.2012
comment
Вы на самом деле даете это или это можно заменить на foobar?   -  person vidstige    schedule 18.07.2012
comment
@DanPuzey не содержит общедоступного определения GetEnumerator.   -  person Ingó Vals    schedule 18.07.2012
comment
@vidstige Да, абсолютно, я не думал об этом как о ключевом слове, когда писал это.   -  person Ingó Vals    schedule 18.07.2012
comment
Хорошо, чтобы быть немного мудаком, я не рассказал всю историю с самого начала. Я использую Caliburn Micro IResult для выполнения сопрограмм. Сомневаюсь, что это актуально, но кто знает.   -  person Ingó Vals    schedule 18.07.2012


Ответы (3)


Если вы хотите, чтобы это был IEnumerator, а не IEnumerable, вам придется выполнить итерацию вручную:

public IEnumerator<IResult> DoStuffIndependently() {
    yield return this;
    yield return that;
}

public IEnumerator<IResult> DoStuffBeforeSometimes() {
    yield return AffectThis;
    yield return AffectThat;

    var dsi = DoStuffIndependently();
    while (dsi.MoveNext()) yield return dsi.Current;
}
person user1096188    schedule 18.07.2012
comment
педантичный момент: вы всегда должны проверять, чтобы удалить итератор. К счастью, с универсальной версией это легко сделать, так как IDisposable гарантировано. - person Marc Gravell; 18.07.2012

Метод — это либо блок итератора (yield return и т. д.), xor обычный метод (return и т. д.). Не может быть и того, и другого. Таким образом, чтобы использовать другой итератор, вы должны повторить его, т.е.

yield return AffectThis;
yield return AffectThat;
using(var iter = DoStuffIndependently()) {
    while(iter.MoveNext()) yield return iter.Current;
}

В качестве альтернативы вы могли бы использовать Concat для объединения двух существующих итераторов.

person Marc Gravell    schedule 18.07.2012
comment
@BrankoDimitrijevic спасибо, исправлю; Я предположил, что это IEnumerable - person Marc Gravell; 18.07.2012
comment
Concat() не работает с IEnumerator, поэтому альтернативное решение не сработает. - person svick; 18.07.2012
comment
@svick, если бы человек выполнял много работы специально с ienumerator (а не с ienumerable), было бы довольно просто добавить метод расширения Concat для итераторов. - person Marc Gravell; 18.07.2012

Используйте IEnumerable вместо IEnumerator и foreach должно работать нормально:

public IEnumerable<IResult> DoStuffIndependently()
{
   yield return This;
   yield return That;
}

public IEnumerable<IResult> DoStuffBeforeSometimes()
{
   yield return AffectThis;
   yield return AffectThat;
   foreach (var x in DoStuffIndependently())
        yield return x;
}

Либо вызовите IEnumerator.MoveNext явно, как Марк предложил.

person Branko Dimitrijevic    schedule 18.07.2012