Another consideration: if you use the IEnumerable method that implements yield , which internally throws an exception, you cannot catch this separate error and continue the enumeration - see the section "Exception Handling" at https://msdn.microsoft.com/en-us/ library / 9k7k7cf0.aspx
Example:
void Main() { // even is okay, odd will cause exception var operations = new[] { 2, 16, 5 /* ! */, 8, 91 /* ! */ }; var results = process(operations); var en = results.GetEnumerator(); "Regular Enumeration".Title(); testEnumeration(en); results = process(operations, ex => log("Handled: {0}", ex.Message)); en = results.GetEnumerator(); "Handled Exceptions".Title(); testEnumeration(en); results = process(operations, ex => log("Handled+: {0}", ex.Message), true); en = results.GetEnumerator(); "Handled Exceptions and Continue".Title(); testEnumeration(en); } /// run the test and debug results void testEnumeration(IEnumerator en) { int successCount = 0, failCount = 0; bool keepGoing = false; do { try { log("==={0}===", "before next"); keepGoing = en.MoveNext(); log("==={0}=== (keepGoing={1}, curr={2})", "after next", keepGoing, en.Current); // did we have anything? if(keepGoing) { var curr = en.Current; log("==={0}===", "after curr"); log("We did it? {0}", curr); successCount++; } } catch(InvalidOperationException iopex) { log(iopex.Message); failCount++; } } while(keepGoing); log("Successes={0}, Fails={1}", successCount, failCount); } /// enumerable that will stop completely on errors IEnumerable<int> process(IEnumerable<int> stuff) { foreach(var thing in stuff) { if(thing % 2 == 1) { throw new InvalidOperationException("Aww, you broked it"); } yield return thing; } } /// enumerable that can yield from exceptions IEnumerable<int> process(IEnumerable<int> stuff, Action<Exception> handleException, bool yieldOnExceptions = false) { bool shouldYield = false; foreach(var thing in stuff) { var result = thing; try { if(thing % 2 == 1) { throw new InvalidOperationException("Aww, you broked it"); } shouldYield = true; } catch(Exception ex) { handleException(ex); // `yield break` to stop loop shouldYield = yieldOnExceptions; if(yieldOnExceptions) result = -1; // so it returns a different result you could interpret differently } if(shouldYield) yield return result; } } void log(string message, params object[] tokens) { Console.WriteLine(message, tokens); }
leads to
Regular Enumeration --------------------------- ===before next=== ===after next=== (keepGoing=True, curr=2) ===after curr=== We did it? 2 ===before next=== ===after next=== (keepGoing=True, curr=16) ===after curr=== We did it? 16 ===before next=== Aww, you broked it ===before next=== ===after next=== (keepGoing=False, curr=16) Successes=2, Fails=1 Handled Exceptions -------------------------- ===before next=== ===after next=== (keepGoing=True, curr=2) ===after curr=== We did it? 2 ===before next=== ===after next=== (keepGoing=True, curr=16) ===after curr=== We did it? 16 ===before next=== Handled: Aww, you broked it ===after next=== (keepGoing=True, curr=8) ===after curr=== We did it? 8 ===before next=== Handled: Aww, you broked it ===after next=== (keepGoing=False, curr=8) Successes=3, Fails=0 Handled Exceptions and Continue --------------------------------------- ===before next=== ===after next=== (keepGoing=True, curr=2) ===after curr=== We did it? 2 ===before next=== ===after next=== (keepGoing=True, curr=16) ===after curr=== We did it? 16 ===before next=== Handled+: Aww, you broked it ===after next=== (keepGoing=True, curr=-1) ===after curr=== We did it? -1 ===before next=== ===after next=== (keepGoing=True, curr=8) ===after curr=== We did it? 8 ===before next=== Handled+: Aww, you broked it ===after next=== (keepGoing=True, curr=-1) ===after curr=== We did it? -1 ===before next=== ===after next=== (keepGoing=False, curr=-1) Successes=5, Fails=0
Note that the Current enumerator is stuck in the last successful MoveNext during the regular enumeration, while the processed exceptions allow it to complete the loop.