Перенос вызова итератора в try / catch при использовании yield

Мне нужно реализовать тяжелую, несколько хрупкую логику в методе, который я реализую как итератор (используя yield):

public IEnumerable<Things> GetMoreThings() {
    while (goodStuffHappens()) {
        Things moreThingsIWant = TemptFateAgain();
        if (moreThingsIWant.Any())
            yield return moreThingsIWant;
    }
}

В вызывающем методе мне нужно обернуть вызов GetMoreThings в _4 _ / _ 5_ и yield return результат:

try {
    foreach (Things thing in Helpful.GetMoreThings())
        yield return thing;
}

catch (Exception e) {
    //crash, burn
}

Посвященный сразу поймет, что это невозможно - внутри блока _8 _ / _ 9_ не бывает доходности (только _10 _ / _ 11_).

Какие-нибудь рекомендации?


person sq33G    schedule 11.02.2016    source источник
comment
Вы действительно хотите просто игнорировать исключение, или в блоке catch есть код, который вы не показываете?   -  person svick    schedule 11.02.2016
comment
Да, там есть значимый код   -  person sq33G    schedule 11.02.2016


Ответы (3)


Оба ответа здесь были правильными. Для этого нет встроенного ярлыка, вам нужно разделить итератор на while, а не на for цикл, чтобы разделить вызов Enumerator.MoveNext() и использование Enumerator.Current.

IEnumerator<Things> iterator = Helpful.GetMoreThings.GetEnumerator();
bool more = true;

while (more) {
    try {
        more = iterator.MoveNext();
    }
    catch (Exception e) {
        //crash, burn
    }

    if (more)
        yield return iterator.Current;
}
person sq33G    schedule 14.02.2016

Поместите вызов и перечисление Helpful.GetMoreThings() отдельно от yield:

try {
    var results = Helpful.GetMoreThings().ToList();
}
catch (Exception e) {
    //crash, burn
}

foreach (Things thing in results)
    yield return thing;

Что-то такое.

Если вам нужно, чтобы это было ленивым, код становится действительно неприятным. Вы больше не можете использовать foreach. Вам нужно написать цикл итераций вручную, и размер кода взорвется до 20 строк неразборчивого беспорядка. Я знаю, потому что сделал это вчера.

person usr    schedule 11.02.2016
comment
Да мне это нужно, чтобы полениться. В противном случае у меня возникнут проблемы с тем, чтобы придумать вескую причину для этого. - person sq33G; 11.02.2016
comment
Затем сделайте то, что сказано в последнем абзаце: разверните цикл foreach в цикл, написанный вручную. Затем вы можете вызвать MoveNext () с защитой от перехвата и уступить без перехвата. - person usr; 11.02.2016

Вы можете использовать Catch() метод расширения из Ix.Net или просто скопируйте его исходный код под лицензией Apache. Код может выглядеть так:

return Helpful.GetMoreThings().Catch((Exception e) =>
{
    // crash, burn
    return null;
}
person svick    schedule 11.02.2016
comment
Исходный код на самом деле представляет собой 20 неразборчивых строк беспорядка, упомянутых выше в ответе от @usr. - person sq33G; 11.02.2016