简体   繁体   English

使用异常过滤器有什么好处,我应该什么时候使用它们?

[英]What is the advantage of using Exception filters and when should I use them?

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.请像我5岁那样解释。

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@domain.com";
}

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;
        }

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.正如 Thomas Levesque 在他的博客中指出的那样,异常过滤器不会展开堆栈。 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.因此,在调试程序时,如果在 try 块中抛出异常,则使用异常过滤器,您将能够查看 try 块中值的状态。 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.如果您没有使用异常过滤器,您的代码将进入 catch 块,并且您将丢失有关 try 块中变量状态的信息。

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;除非您像throw exception;那样明确地重新抛出异常,否则堆栈跟踪将保持不变throw exception; in a catch block where exception is the caught exception.exception是捕获的异常的 catch 块中。

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.因此,虽然在某些情况下,您可以将其视为可能会或可能不会使您的代码更清晰的东西(取决于您对语法的看法),但它确实会改变行为。

Exception filters have been added to C# because they were in Visual Basic and the "Roslyn" team found them useful when developing "Roslyn".异常过滤器已添加到C# 中,因为它们在Visual Basic 中,并且“Roslyn”团队在开发“Roslyn”时发现它们很有用。

Beware that the filter runs in the context of the throw and not in the context of the catch .请注意过滤器在throw的上下文中运行,而不是在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 .如果ex.Number不是2则不会捕获并重新抛出异常。 It's just not caught if ex.Number is not 2 .如果ex.Number不是2它就不会被捕获。

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. UPD:正如 Paulo Morgado 在回答中指出的那样,该功能已经在 CLR 中使用了很长时间,而 C# 6.0 仅为其添加了语法支持。 My understanding of it, however, remains as a syntactic sugar, eg 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.在这里你可以清楚地看到第一个和第二个异常是在各自的块中处理的,这些块是用when protection 分开的,而一个全局的 catch-all 块只会捕获第三个异常。 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;
                    }

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM