为什么未使用的变量没有警告?

19

在Windows上使用VS2010、VS2008或MonoDevelop编译以下程序时,我得到了警告CS0219,“变量'y'被赋值,但其值从未使用”。

namespace Problem
{
    public class Program
    {        
        private static void Main(string[] args)
        {
            object x = new object();
            int y = 0;
        }
    }
}

为什么在Visual Studio编译时x没有警告?

有趣的是,在Mac OS X上使用MonoDevelop进行编译时,xy都会得到CS0219警告。

7个回答

26

事实证明,当赋值操作的右侧不是编译时常量时,此警告会被抑制。

微软Visual Studio反馈网站上已删除的帖子解释了这是因为他们收到了许多来自那些只是为了在调试期间查看方法返回结果而分配变量的人的投诉,并发现这个警告很烦人:

在这种情况下抑制“已分配但从未使用”警告的原因是基于用户反馈,即这样的用例:

int Blah(){
    // blah
    BlahBlah(x, y, z)
    // blah
    // blah
}

"嘿," 调试时用户说道, "我想知道BlahBlah返回了什么?" 但是在调试器中没有简单的方法可以检查返回值,所以用户经常会这样做:

int Blah()
{
    // blah
    int temp = BlahBlah(x, y, z)
    // blah
    // blah
}

然后使用本地变量或查看窗口来检查temp。在函数中没有其他地方使用temp,因此会产生令人烦恼的“已分配但未使用”的警告。

我认为这有点可惜,因为:

  1. 当这些警告在MonoDevelop中给出时,它们实际上很有帮助。
  2. 任何人都可以自己抑制警告(诚然,他们还将抑制未使用的编译时常量分配的警告 - 也许应该有一个单独的警告?)。

无论如何,我理解你不能让每个人都满意。


4
现在您可以在Visual Studio调试器中查看返回值,是否仍有禁用此警告的原因? - pancakes
8
有没有办法重新开启警告? - Xonatron
4
我来这里问是否有人知道如何重新开启警告...这是因为开发者初始化了一些占用资源很多但并未使用的变量(所谓"占用资源很多"是指实例化了一个类,其功能过于复杂而无需使用)。 - Nelson Rodriguez
2
无论如何,我明白你不能取悦每个人。这并不像存在用户可以设置的选项¯\(ツ)/¯。 - bugybunny
1
@Ergwun 这不是针对你的,抱歉。更像是个玩笑,微软可以添加一个选项,用于生成警告。 - bugybunny
显示剩余5条评论

2

我可能有点偏离主题,但我认为这是因为 y 只被设置了值,而 x 被实例化为非平凡的东西 - 实例化可能涉及 New() 方法中的单独操作,并且由于实例化变量可能具有副作用,因此它不被认为是未使用的。在您的情况下,它只是一个基本对象(base object()),因此没有影响,但是也许编译器不够聪明,无法区分。

另一方面,对于 y,实例化没有副作用,因此被认为是未使用的 - 如果完全删除它,则应用程序的代码路径将不会改变。


3
但是您可以保留new object()的调用,而不将结果赋值给变量。 - phoog

2

我猜测,由于x是一个引用类型,编译器没有显示任何警告,因为构造函数可能执行一些完全“有意义”的操作;相反,y是一个值类型,其值只被赋值但从未被使用,因此编译器很容易告诉你如果你不打算在后面使用它则毫无意义。


这很有道理,但你会认为编译器应该知道像 object 这样的系统对象不会产生副作用。 - Gort the Robot
1
@StevenBurnap编译器在处理像这样的“显而易见”的信息时并不是很聪明。通常这是因为增加逻辑来跟踪这些信息的好处(小)不足以抵消编译器复杂度的成本(大)。 - phoog
我对这个答案并不满意。运行编译器的效果可以通过以下方式保留:void Main(string[] args) { new object(); int y = 0; } - phoog
2
@StevenBurnap 创建一个新的 object 确实 会产生副作用:它会分配内存。如果没有其他影响,它会产生内存压力——这可能是您的意图。编译器绝不会“知道”当存在副作用时却“没有副作用”。 - Joe White
我的先前评论应该是“运行构造函数”的影响,而不是“编译器”! - phoog

1

ReSharper 还会警告您 x 未被使用。


0

y在堆栈上,x在堆上(提示:x使用new关键字)。因此,一些调试器/编译器警告可能认为堆/全局变量(如x)应由程序员自行处理,因为低级代码或调试探针可能在幕后操作它们。但是,像y这样的堆栈变量完全在编译器的控制下,并且很容易能够证明检测到未使用的冗余变量。


0

可能是因为x是引用类型,因此存储在堆上,它会防止该对象的垃圾回收,直到x超出作用域。

例如:

void main(string[] args)
{
    object x = new object();
    while (true)
    {
        // Some threading stuff
        // x is never garbage collected
    }
}

与之相反:

void main(string[] args)
{
    new object();
    while (true)
    {
        // Some threading stuff
        // The unreferenced object IS garbage collected
    }
}

1
据我所知,这仅适用于在调试器中运行的情况,在这种情况下,运行时将局部变量的存活范围扩展到整个方法。在发布模式下,它们可以更短 - 或在这种情况下完全消除。 - Mikayla Hutchinson

-1

Eclipse 将会将该情况视为未使用。


Eclipse是一个Java IDE。这个问题是关于C#的。 - Charles Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接