Dies ist eine sehr interessante Frage.
Daran erinnern, dass in Linq viele Standard-Operatoren zur Verfügung gestellt werden, die effektiv miteinander verketten. Es gibt derzeit keine Möglichkeit, die benutzerdefinierte Ausnahmebehandlung um eine innere Sequenz zu wickeln.
So ist mein Vorschlag, eine neue zu schreiben, die Sie eine Aktion angeben können, die jede Ausnahme behandelt, die während der Ausführung von IEnumerator.MoveNext
auftritt:
public static class EnumerableExceptions
{
public static IEnumerable<TItem> Catch<TItem, TEx>(
this IEnumerable<TItem> source,
Action<TEx> handler) where TEx : Exception
{
using (var enumerator = source.GetEnumerator())
{
for (; ;)
{
try
{
if (!enumerator.MoveNext())
yield break;
}
catch (TEx x)
{
handler(x);
yield break;
}
yield return enumerator.Current;
}
}
}
}
So, jetzt angenommen wir dies hatte:
public class NastyException : Exception { }
public static IEnumerable<String> StringYielder()
{
yield return "apple";
yield return "banana";
throw new NastyException();
yield return "oracle";
yield return "grapefruit";
yield return "microsoft";
}
Wir würden gerne in der Lage sein, den ganzen Körper in eine try
/catch
wickeln, die leider illegal ist. Aber was können wir tun, ist die erzeugte Sequenz wickeln:
public static IEnumerable<String> LoggingStringYielder()
{
return StringYielder().Catch(
(NastyException ex) =>
Console.WriteLine("Exception caught: " + ex.StackTrace));
}
Das heißt, erhalte ich eine Sequenz, die durch die „rohen“ StringYielder
Methode aufrufen, und dann wende ich den neuen Catch
Operator es, die festlegen, was zu tun, wenn Ein bestimmter Ausnahmetyp tritt auf. Hier werde ich nur den Stack-Trace drucken.
Also, wenn ich dies tun:
foreach (var str in LoggingStringYielder())
Console.WriteLine(str);
Das Programm beendet, ohne abzustürzen, und der Ausgang ist:
apple
banana
Exception caught: at ConsoleApplication7.Program.<StringYielder>.. blah
So, obwohl Sie nicht einen Versuch catch um den Code in das setzen kann Original-Iterator-Methode, können Sie sie jetzt außerhalb der Iterator-Methode umschließen. Es ist wie eine nicht-intrusive Möglichkeit, die Ausnahmebehandlung um den Code zwischen jeweils yield return
zu injizieren.
Bonusupdate!
Um wirklich pingelig zu sein, die ich über die Art und Weise, dass letzte Satz lautet:
Zum einen können Sie vor dem ersten yield return
werfen und es wird auf die gleiche Art und Weise behandelt, wie der Code in dem ersten Aufruf führt zu MoveNext
. Also "... der Code vor jeder ..." wäre genauer als "... der Code zwischen jeder ..." gewesen.
Zweitens kann ein yield return
einen Ausdruck akzeptieren, der ausgewertet werden muss und der während der Auswertung ausgelöst werden kann. Das sollte als Code betrachtet werden, der ausgeführt wird, bevor das yield return
auftritt, obwohl es syntaktisch danach erscheint.
Ok, ich habe die Frage aktualisiert, um zu reflektieren, dass ich die Ausnahme erhalten möchte, _wenn man geworfen wurde. Trotzdem, Fang ist nicht erlaubt um den Ertrag ... – KristoferA