I have a foreach
loop that breaks during the loop in the condition of the foreach itself. Is there a way to try catch
the item that throws the exception and then continue the loop?
This will run a few times until the exception hits and then end.
try {
foreach(b in bees) { //exception is in this line
string += b;
}
} catch {
//error
}
This will not run at all because the exception is in the condition of the foreach
foreach(b in bees) { //exception is in this line
try {
string += b;
} catch {
//error
}
}
I know some of you are going to ask how this is happening so here is this:
Exception PrincipalOperationException
is being thrown because a Principal
(b in my example) cannot be found in GroupPrincipal
(bees).
Edit: I added the code below. I also figured out that one group member was pointing to a domain that no longer exists. I easily fixed this by deleting the member but my question still stands. How do you handle exceptions that are thrown inside the condition of a foreach?
PrincipalContext ctx = new PrincipalContext(ContextType.domain);
GroupPrincipal gp1 = GroupPrincipal.FindByIdentity(ctx, "gp1");
GroupPrincipal gp2 = GroupPrincipal.FindByIdentity(ctx, "gp2");
var principals = gp1.Members.Union(gp2.Members);
foreach(Principal principal in principals) { //error is here
//do stuff
}
ForEach overloads do not have any special mechanism to handle exceptions that might be thrown. In this respect, they resemble regular for and foreach loops ( For and For Each in Visual Basic); an unhandled exception causes the loop to terminate as soon as all currently running iterations finish.
When you add your own exception-handling logic to parallel loops, each exception should be catched and saved to a list(Use Concurrent Queue), because each loop will create different exception. So after the loop exists we can wrap all exceptions from the list in a System. AggregateException and throw it.
You have to build a try-catch-block inside your loop and don't throw the exception again. I need the outer try-catch-block as there are chance for exception to occur in the outer part, and also need to throw the exception as I need to log the process.
Almost the same as the answer from @Guillaume, but "I like mine better":
public static class Extensions
{
public static IEnumerable<T> TryForEach<T>(this IEnumerable<T> sequence, Action<Exception> handler)
{
if (sequence == null)
{
throw new ArgumentNullException("sequence");
}
if (handler == null)
{
throw new ArgumentNullException("handler");
}
var mover = sequence.GetEnumerator();
bool more;
try
{
more = mover.MoveNext();
}
catch (Exception e)
{
handler(e);
yield break;
}
while (more)
{
yield return mover.Current;
try
{
more = mover.MoveNext();
}
catch (Exception e)
{
handler(e);
yield break;
}
}
}
}
Maybe you can try to create a method like that:
public IEnumerable<T> TryForEach<T>(IEnumerable<T> list, Action executeCatch)
{
if (list == null) { executeCatch(); }
IEnumerator<T> enumerator = list.GetEnumerator();
bool success = false;
do
{
try
{
success = enumerator.MoveNext();
}
catch
{
executeCatch();
success = false;
}
if (success)
{
T item = enumerator.Current;
yield return item;
}
} while (success);
}
and you can use it this way:
foreach (var bee in TryForEach(bees.GetMembers(), () => { Console.WriteLine("Error!"); }))
{
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With