Reputation: 492
Comparing the old way versus the new way of error handling, by using Exception filters, what is exactly the advantage for me of using filters and when should I use it? is there an scenario where I can get a good advantage of this new feature?
I have read about the unwinding stack but still I don't get the scenario where we can not handle that under the old way. Explain like I'm 5 please.
try
{
Foo.DoSomethingThatMightFail(null);
}
catch (MyException ex) when (ex.Code == 42)
{
Console.WriteLine("Error 42 occurred");
}
vs
try
{
Foo.DoSomethingThatMightFail(null);
}
catch (MyException ex)
{
if (ex.Code == 42)
Console.WriteLine("Error 42 occurred");
else
throw;
}
I know there is other version of this question, the problem is, that the question mention benefits that I cant actually find, for instance.
Exception filters are preferable to catching and rethrowing because they leave the stack unharmed. If the exception later causes the stack to be dumped, you can see where it originally came from, rather than just the last place it was rethrown.
after doing some testing, I did not see the difference between both, I still see the exception from the place it was rethrown. So, or the information is not confirmed, I don't understand the Exception filters( that is why I am asking), or I am doing it wrong (also please correct me if I am wrong).
class specialException : Exception
{
public DateTime sentDateTime { get; } = DateTime.Now;
public int code { get; } = 0;
public string emailsToAlert { get; } = "[email protected]";
}
then:
try
{
throw new specialException();
//throw new Exception("Weird exception");
//int a = Int32.Parse("fail");
}
catch (specialException e) when(e.code == 0)
{
WriteLine("E.code 0");
throw;
//throw e;
}
catch (FormatException e)
{
if (cond1)
{
WriteLine("cond1 " + e.GetBaseException().Message+" - "+e.StackTrace);
throw;
}
throw;
}
catch (Exception e) //when (cond2)
{
Console.WriteLine("cond2! " + e.Message);
throw;
}
Upvotes: 2
Views: 2084
Reputation: 32702
I don't understand Paulo's answer. He may be correct or he may not be.
I definitely disagree with Alexander's answer. It is not just syntactic sugar. Pure syntactic sugar means it's solely an easier way of writing something, and that execution will be unchanged.
However, that's not the case in this situation. As Thomas Levesque points out in his blog, exception filters do not unwind the stack. So when debugging the program, if you have an exception thrown in your try block, with exception filters you'll be able to see what the state of the values are in the try block. If you weren't using exception filters, your code would enter the catch block and you would lose information about the state of the variables in the try block.
Note that I'm not talking about the stacktrace (it's a different but related concept to the stack). The stacktrace would be unchanged unless you explicitly did rethrow the exception as in throw exception;
in a catch block where exception
is the caught exception.
So while in some cases you can think of it as something that may or may not make your code cleaner (depending on your opinion of the syntax), it does change the behavior.
Upvotes: 5
Reputation: 14856
Exception filters have been added to C# because they were in Visual Basic and the "Roslyn" team found them useful when developing "Roslyn".
Beware that the filter runs in the context of the throw
and not in the context of the catch
.
Anyhow, one use might be something like this:
try
{
//...
}
catch (SqlException ex) when (ex.Number == 2)
{
// ...
}
catch (SqlException ex)
{
// ...
}
Edited:
One might think this is just syntactic sugar over this:
try
{
//...
}
catch (SqlException ex) when (ex.Number == 2)
{
// ...
}
catch (SqlException ex)
{
if (ex.Number == 2)
{
// ...
}
else
{
// ...
}
}
But if we change the code for this:
try
{
//...
}
catch (SqlException ex) when (ex.Number == 2)
{
// ...
}
It will be more like this:
try
{
//...
}
catch (SqlException ex) when (ex.Number == 2)
{
// ...
}
catch (SqlException ex)
{
if (ex.Number == 2)
{
// ...
}
else
{
throw
}
}
But there's one fundamental difference. The exception is not caught and rethrown if ex.Number
is not 2
. It's just not caught if ex.Number
is not 2
.
Upvotes: 0
Reputation: 12554
UPD: As pointed out in the answer by Paulo Morgado, the feature has been in CLR for quite some time and C# 6.0 only added syntax support for it. My understanding of it, however, remains as a syntactic sugar, e.g. the syntax that allows me to filter exceptions in a nicer way than it used to be, irrespective of how the previous "straightforward" method works under the hood.
=====
In my understanding, this is a syntactic sugar that allows you to more clearly define the block there your exception is going to be handled.
Consider the following code:
try
{
try
{
throw new ArgumentException() { Source = "One" };
throw new ArgumentException() { Source = "Two" };
throw new ArgumentException() { Source = "Three" };
}
catch (ArgumentException ex) when (ex.Source.StartsWith("One")) // local
{
Console.WriteLine("This error is handled locally");
}
catch (ArgumentException ex) when (ex.Source.StartsWith("Two")) // separate
{
Console.WriteLine("This error is handled locally");
}
}
catch (ArgumentException ex) // global all-catcher
{
Console.WriteLine("This error is handled globally");
}
Here you can clearly see that first and second exception are handled in the respective blocks that are separated using when
safeguard, whereas the one global catch-all block will catch only the third exception. The syntax is clearer that catching all the exceptions in every block, something like:
catch (ArgumentException ex) // local
{
if (ex.Source.StartsWith("One"))
{
Console.WriteLine("This error is handled locally");
}
else
{
throw;
}
}
Upvotes: -1