【问题标题】:How compiler optimize exception filters in c#?编译器如何优化 c# 中的异常过滤器?
【发布时间】:2015-11-24 11:45:57
【问题描述】:

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

项目属性 -> 构建 -> 勾选“优化代码”。运行应用程序。获取无限循环。 这是正确的行为还是编译器中的错误?

更新1: 所以这似乎是非常罕见的情况,有 unar 递减和重新抛出异常。 在 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);

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

【问题讨论】:

  • 我刚刚在 VS 2015 中新创建的 web 表单 asp.net 项目中尝试了它,一切都按预期工作。似乎您的特定配置受到影响(或者在为 SO 采用代码时,您意外删除了错误部分)。但无论如何,以这种方式使用过滤器是个坏主意。
  • 你尝试发布配置吗?
  • 创建一个测试project
  • 是的,在发布和调试中工作正常

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


【解决方案1】:

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

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

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

代码:

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

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

【讨论】:

  • 会同意你的回答,因为在最合适的用途(见我的更新)它可以工作。
【解决方案2】:

快速修复。你可以在 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);
}

好的。我现在可以说那是一个错误。测试表明您的代码在 32 位模式下运行良好。但不适用于 64 位模式。

【讨论】:

  • 是的,我们可以。但我不明白为什么当我们“优化代码”时行为会发生变化
  • 好的。并非一切都完美无缺。即使在.Net ;) 这可能是一个错误。 @OlegAlekseenko
猜你喜欢
  • 2014-02-21
  • 1970-01-01
  • 2018-07-08
  • 2012-09-06
  • 2013-10-23
  • 1970-01-01
  • 2012-02-09
相关资源
最近更新 更多