Reputation: 130
In C# 6 appears exception filters. So we can write some retry logic as
public static void Retry()
{
int i = 3;
do
{
try
{
throw new Exception();
}
catch (Exception) when (--i < 0)
{
throw;
}
catch (Exception)
{
Thread.Sleep(10);
}
} while (true);
}
In console app it works great. But if we create website app with "optimize code" there will be infinite loop, because value of 'i' never changes. Without "optimize code" this worked as expected. How to test: Create in empty asp.net website application (i try .net 4.5.2 and .net 4.6). add this code to global application class
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
int i = 3;
do
{
try
{
throw new Exception();
}
catch (Exception) when (--i < 0)
{
throw;
}
catch (Exception)
{
Thread.Sleep(10);
}
} while (true);
}
}
Project properties -> Build -> check "optimize code". Run application. Get Infinite loop. Is this right behaivior or it'a bug in compiller?
Upd1:
So it's seems very rare condition with unar decrement and rethrowing exception.
repeated while compile in VS 2015 on windows 7 (try it on several machines). In VS2015 on windows 10 works fine.
Also it's work if change code like this
int i = 3;
do
{
try
{
throw new Exception();
}
catch (Exception) when (--i > 0)
{
Thread.Sleep(10);
}
} while (true);
which will be more suitable in real world example (because unwinded stack)
Upvotes: 4
Views: 202
Reputation: 19169
A quick fix. You can move your decrement logic inside catch. And reduce counter by 1.
public static void Retry()
{
int i = 3 - 1;
do
{
try
{
throw new Exception();
}
catch (Exception) when (i < 0)
{
throw;
}
catch (Exception)
{
i--;
Thread.Sleep(10);
}
} while (true);
}
Ok. i can say thats a bug now. The tests shows your code works fine in 32bit mode. but not works in 64bit mode.
Upvotes: 0
Reputation: 113342
I think that may be a bug. You should report it as such, IMO. Whether it is or not though I wouldn't advise you take this approach.
Firstly, you are side-effecting in your exception filter. That's probably a bad practice generally. Think of it in CQS terms; the filter is a query, not a command.
Secondly, you don't really gain anything. Because you are catching the same exception in the next block, what do you gain from exception-filter behaviour (no stack unwinding if not matched) over just putting the logic into the second catch block? Nothing.
The code:
int i = 3;
do
{
try
{
throw new Exception();
}
catch (Exception)
{
if (--i < 0)
throw;
Thread.Sleep(10);
}
} while (true);
Expresses idea that you always want to catch the exception, but you want to behave differently in the face of that exception being caught depending on other conditions. This makes it better express the retry concept than an exception filter, which expresses the idea that you only want to catch the exception at all, depending on other conditions.
Upvotes: 2