编译器如何在c#中优化异常过滤器?

时间:2015-11-24 11:45:58

标签: c# asp.net exception-handling c#-6.0

在C#6中出现异常过滤器。所以我们可以写一些重试逻辑

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

在控制台应用程序中它运行良好。 但是如果我们用“优化代码”创建网站应用程序,那么将会有无限循环,因为'i'的值永远不会改变。没有“优化代码”,这按预期工作。 如何测试: 在空的asp.net网站应用程序中创建(我尝试.net 4.5.2和.net 4.6)。将此代码添加到全局应用程序类

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

项目属性 - &gt;构建 - &gt;检查“优化代码”。运行应用程序获得无限循环。 这是正确的行为还是在compiller中的错误?

Upd1: 所以这似乎非常罕见的情况下,未经减少和重新抛出异常。 在Windows 7上的VS 2015中编译时重复(在几台机器上试用)。在Windows 10的VS2015中工作正常 如果更改这样的代码

也可以
int i = 3;
   do
   {
       try
       {
          throw new Exception();
       }
       catch (Exception) when (--i > 0)
       {
          Thread.Sleep(10);
       }
   } while (true);

这将更适合现实世界的例子(因为未展开的堆栈)

2 个答案:

答案 0 :(得分:2)

我认为这可能是一个错误。你应该这样报告,IMO。不管是不是,我都不建议你采用这种方法。

首先,您在异常过滤器中有副作用。这通常可能是一种不好的做法。用CQS术语来思考它;过滤器是查询,而不是命令。

其次,你并没有真正获得任何收益。因为你在下一个块中捕获了相同的异常,所以你从异常过滤器行为中获得了什么(如果不匹配则没有堆栈展开)而只是将逻辑放入第二个catch块?什么都没有。

代码:

int i = 3;
do
{
  try
  {
    throw new Exception();
  }
  catch (Exception)
  {
    if (--i < 0)
      throw;
    Thread.Sleep(10);
  }
} while (true);

表示您总是希望捕获异常,但是在面对被捕获的异常时,您希望采取不同的行为,具体取决于其他条件。这使得它比异常过滤器更好地表达重试概念,异常过滤器表达了根据其他条件你只想捕获异常的想法。

答案 1 :(得分:0)

快速修复。你可以将你的减量逻辑移到catch中。并将计数器减少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);
}

确定。我现在可以说这是一个bug。测试表明您的代码在32位模式下工作正常。但不适用于64位模式。