Reputation: 4662
I have not worked in C# 6 yet but was wondering....
As the title says "What happens if the filter of an Exception filter throws an exception?". I guess the really answer is "The filter should be written in such a way that it never throws an exception.", but lets say it does. Will it be as if the exception happened inside the catch itself?
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) when (MethodThatThrowsAnException())
{
WriteLine("Filtered handler 1");
}
catch (Exception ex)
{
WriteLine("Filtered handler 2");
}
Or
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) when (MethodThatThrowsAnException())
{
WriteLine("Filtered handler 1");
}
Edit: Interesting Example This section was removed because of a bug in alleged volatileread upon which the example was based. Further investigation is required
Upvotes: 25
Views: 3389
Reputation: 44448
You can try it out here.
As @Habib correctly indicates, the filter simply gets skipped and it's as if it never existed. From that point on, the catch clauses work as they always have. The example above demonstrates this.
However if you change the second catch clause to a type that cannot catch whatever is thrown from your method, your program will crash because of an unhandled exception.
Spicy detail (bug): if you call the method encompassing the try-catch via reflection and a when
clause throws an exception then it will be this exception that is considered unhandled and not the original one. More information here.
Upvotes: 4
Reputation: 223322
Exception raised in exception filter will be ignored and it will cause the filter to fail.
Exception filters are feature of CLR since v1.0. Eariler they were available with VB.Net an F#. As far as swallowing/ignoring exceptions in filter method is concerned, that is also a defined behavior and unlikely to change in recent future.
Original exception will move down to other catch blocks or will remain un-handled in case of not being caught by any.
Consider the following code example:
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) if (MethodThatThrowsAnException())
{
WriteLine("Filtered handler 1");
}
catch (IndexOutOfRangeException ex)
{
WriteLine("Index Out of Range");
}
and the method:
static bool MethodThatThrowsAnException()
{
throw new IndexOutOfRangeException("Index Out of Range");
}
Although the method is throwing IndexOutOfRangeException
and there is a catch
block in the caller code for that specific exception but the exception from the method will never make it to the caller. IndexOutOfRangeException
from filter method will be ignored and since the original exception throw new Exception("Forced Exception");
from the first line isn't handled anywhere, The program will crash because of Unhandled Exception "Forced Exception".
In your first code snippet, since you have a catch block for base Exception
, your original exception from the first line throw new Exception("Forced Exception");
will be caught and handled there. You will not notice the exception thrown earlier in the filter method.
Upvotes: 0
Reputation: 4662
Edit: The oddness seems to be caused by a bug in volatileread. Please refer to poke's answer. The experiments below can not be trusted
So I ran a few experiments that gave a few interesting results to shed some light on the issue.
Check using http://volatileread.com/utilitylibrary/snippetcompiler?id=7632
public void Main()
{
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) when (MethodThatThrowsAnException())
{
Console.WriteLine("Filtered handler 1");
}
catch (Exception ex)
{
Console.WriteLine("Filtered handler 2");
}
}
private bool MethodThatThrowsAnException()
{
throw new Exception();
}
Prints out "Filtered handler 2"
public void Main()
{
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) when (MethodThatThrowsAnException())
{
Console.WriteLine("Filtered handler 1");
}
}
private bool MethodThatThrowsAnException()
{
throw new Exception("MethodThatThrowsAnException");
}
Prints out:
Unhandled Expecption: System.Exception: MethodThatThrowsAnException
at Program.MethodThatThrowsAnException() at Program.Main()
Another interesting output for
public void Main()
{
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) when(MethodThatThrowsAnException())
{
Console.WriteLine("Filtered handler 1");
}
catch (Exception ex) when(MethodThatThrowsAnException2())
{
Console.WriteLine("Filtered handler 2");
}
}
private bool MethodThatThrowsAnException()
{
throw new Exception("MethodThatThrowsAnException");
}
private bool MethodThatThrowsAnException2()
{
throw new Exception("MethodThatThrowsAnException2");
}
Unhandled Expecption: System.Exception: MethodThatThrowsAnException2 at Program.MethodThatThrowsAnException2() at Program.Main()
So it seems like it tries to evaluated the first catch if it throws an exception it continues to the next catch. The first catch that does not fail and matches all conditions then handles the exception (BTW an exception of the type originally thrown in the try). However if the last catch that is of the type of the thrown error also throws an exception in the filter part then an Unhandled Exception is thrown of the type in the filter.
Edit: Note:
public void Main()
{
try
{
try
{
throw new Exception("Forced Exception");
}
catch (Exception ex) when (MethodThatThrowsAnException())
{
Console.WriteLine("Filtered handler 1");
}
}
catch (Exception ex)
{
Console.WriteLine("Caught");
Console.WriteLine(ex);
}
}
private bool MethodThatThrowsAnException()
{
throw new Exception("MethodThatThrowsAnException");
}
Outputs:
Caught
System.Exception: Forced Exception at Program.Main()
If you compare that with the second output... HOW THE HELL IS THAT POSSIBLE??? In the second example MethodThatThrowsAnException is thrown but in the last example "Forced Exception" is caught
Upvotes: 3
Reputation: 388123
If there is an exception thrown within the filter, then that exception will be silently swallowed and the filter simply fails. This causes the original exception to go down the catch
cases or ultimately end up being reraised upwards.
So the code calling the filter will not have a way to know that there was actually an exception within your filter method. Thus, it’s important to avoid conditions where an exception can be thrown to make sure that a filter doesn’t fail for this reason.
You can verify this using the following code on volatileread.com’s C# 6 beta interpreter:
public void Main ()
{
try
{
try
{
throw new Exception("Original exception");
}
catch (Exception ex)
when (Test()) // `if (Test())` in older previews
{
Console.WriteLine("Caught the exception");
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public static bool Test ()
{
throw new Exception("Exception in filter condition");
}
This results in the “Original exception” appearing in the outer try/catch block.
Since I didn’t understand the output from volatileread’s compiler when not using the outer try/catch block, I installed the MS Build Tools 2015 myself (which as of the time of this answer still uses if
, not when
) and tried it out. It turns out that when not using the outer try/catch, the “original exception” is still the one that causes the program to crash. So it’s not the filter exception. This seems to be a bug with volatile’s compiler.
Upvotes: 14