我的团队中有人试图修复空 catch 子句中的“变量未使用”警告。
try { ... } catch (Exception ex) { }
-> 给出有关未使用 ex
的警告。到目前为止,还不错。
修复是这样的:
try { ... } catch (Exception ex) { string s = ex.Message; }
看到这个,我想“太棒了,所以现在编译器会提示 没有被使用。”
但事实并非如此!那段代码没有警告,我不明白为什么。有什么想法吗?
附言。我知道禁止异常的包罗万象的条款是一件坏事,但那是另一个话题。我也知道通过这样做可以更好地消除初始警告,这也不是重点。
try { ... } catch (Exception) { }
或
try { ... } catch { }
最佳答案
在这种情况下,编译器检测到 s 已写入但未读取,并且有意抑制警告。
不管你信不信,原因是因为 C# 是一种垃圾收集语言。
你怎么想的?
好吧,请考虑以下内容。
您有一个程序调用返回字符串的方法 DoIt()。您没有 DoIt() 的源代码,但您希望在调试器中检查它的返回值是什么。
现在在您的特定情况下,您使用 DoIt() 是为了它的副作用,而不是它的返回值。所以你说
DoIt(); // discard the return value
现在你正在调试你的程序,你去查看 DoIt() 的返回值,它不在那里,因为当调试器在调用 DoIt() 后中断时,垃圾收集器可能已经已经清理了未使用的字符串。
事实上,托管调试器没有“查看前一个方法调用返回的内容”的工具。非托管 C++ 调试器具有该功能,因为它可以查看丢弃的返回值仍然存在的 EAX 寄存器,但您无法在托管代码中保证返回值在被丢弃后仍然存在。
现在,有人可能会争辩说这是一个有用的功能,调试器团队应该添加一个功能,如果在方法执行后立即有调试器断点,则返回值保持有效。那将是一个不错的功能,但我不是要求它的人;去问调试团队。
可怜的 C# 开发人员该怎么办?创建一个局部变量,将结果存储在局部变量中,然后在调试器中检查局部。调试器确实确保局部变量不会被积极地垃圾收集。
所以你这样做,然后编译器给你一个警告,你有一个只写入而永远不会读取的本地因为读取的东西不是程序的一部分,它是开发人员坐着的在那里看着调试器。这是一个非常恼人的用户体验!因此,我们检测到将非常量 值分配给从未读取 的局部变量或字段 的情况,并抑制该警告.如果你改变你的代码,让它变成 string s = "hello";
那么你会开始收到警告,因为编译器的原因,嗯,这不可能是有人在绕过调试器的局限性,因为值就在那里,开发人员可以在没有调试器的情况下读取它。
这解释了那个。在许多其他情况下,我们会抑制有关从未读取过的变量的警告;一个detailed exegisis of all the compiler's policies因为我们什么时候报告警告,什么时候不报告警告,我会花很多时间来写,所以我想我会把它留在那里。
关于C# 编译器应该发出警告但不发出警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2740885/