代码之家  ›  专栏  ›  技术社区  ›  Cristian Diaconescu

C#编译器应该给出警告,但没有?

  •  18
  • Cristian Diaconescu  · 技术社区  · 16 年前

    我的团队中有人试图修复一个空catch子句中的“variable not used”警告。

    try { ... } catch (Exception ex) { }
    

    -&燃气轮机;警告 ex 没有被使用。到目前为止,还不错。

    修复方法是这样的:

    try { ... } catch (Exception ex) { string s = ex.Message; }
    

    看到这个,我想“太好了,所以现在编译器会抱怨 s

    但事实并非如此!这段代码上没有警告,我也不知道为什么。有什么想法吗?

    try { ... } catch (Exception) { }
    

    或

    try { ... } catch { }
    
    7 回复  |  直到 16 年前
        1
  •  25
  •   Eric Lippert    16 年前

    在这种情况下,编译器检测到s已写入但未读取,并且 故意抑制警告。

    你怎么知道的?

    好吧,考虑以下几点。

    DoIt(); // discard the return value
    

    现在您正在调试您的程序,您可以查看DoIt()的返回值并 因为当调试器在调用DoIt()后中断时,垃圾收集器可能已经清理了未使用的字符串 .

    实际上,托管调试器没有“查看上一个方法调用返回的内容”的功能。非托管C++调试器具有该特性,因为它可以查看EAX登记器,其中丢弃的返回值仍然处于就绪状态,但在托管代码中,如果丢弃的值仍然存在,则不能保证返回值仍然存在。

    可怜的C开发者该怎么办?生成一个局部变量,将结果存储在局部变量中,然后在调试器中检查局部变量。调试器 确保当地人不会被大肆收集垃圾。

    所以你这样做,然后编译器给你一个警告,你有一个本地的,只写,从不读 . 这是一个非常恼人的用户体验!因此我们检测到 非常数 局部变量或字段 阅读 ,并取消显示该警告。如果你把代码改成 string s = "hello"; 然后您将开始得到警告,因为编译器的原因,嗯,这不可能是有人绕过调试器的限制,因为值是 就在那里 开发人员可以在没有调试器的情况下读取它。

    detailed exegisis of all the compiler's policies 因为当我们报告警告和不报告警告的时候,我会花相当长的时间去写,所以我想我就不写了。

        2
  •  9
  •   Gary.Ray    16 年前

    变量s用于。。。保存对ex.Message的引用。如果你只有一根弦;你会得到警告的。

        3
  •  1
  •   Nelson Rothermel    16 年前

    我认为回答这个问题的人需要对编译器的工作原理有所了解。然而,类似FxCop的东西可能会发现这一点。

        4
  •  1
  •   BFree    16 年前

    属性只是方法,没有什么能阻止任何人在ex.Message属性中放入一些代码。因此,虽然您可能没有对s执行任何操作,但调用ex.Message可能有潜在的价值。。。。

        5
  •  1
  •   Dan Diplo    16 年前

    当一个变量可能被使用,也可能不被使用时,编译器的工作并不是计算每个实例和角落的情况。有些容易被发现,有些问题更大。在谨慎方面犯错是明智的做法(尤其是当警告可以被设置为错误时——想象一下,如果只是因为编译器认为您没有使用您正在使用的东西而软件没有编译)。Microsoft编译器团队明确表示:

    “…我们对 有兴趣发现未使用的 警察。它可以发现未使用的字段 更有趣的是 您的代码。”

    Ed Maurer, Development Lead, Managed Compiler Platform

        6
  •  1
  •   Rob Fonseca-Ensor    16 年前

    雷斯哈珀会明白的