37

我的应用程序中有一些配置选项,如下所示

const bool ExecuteThis=true;
const bool ExecuteThat=false;

然后使用它的代码就像

if(ExecuteThis){ DoThis(); }
if(ExecuteThat){ DoThat(); } //unreachable code warning here

问题是,我们可能会发布稍微不同的版本,而不是 ExecuteThis 或 ExecuteThat,我们希望能够使用 const,这样我们在运行时就不会受到此类事情的任何速度损失。但我厌倦了看到有关无法访问代码的警告。我是一个喜欢消除所有警告的人,但我对此无能为力。有什么选项可以用来关闭这些警告吗?

4

8 回答 8

59

要禁用:

#pragma warning disable 0162

恢复:

#pragma warning restore 0162

有关详细信息#pragma warning,请参阅MSDN

请注意,C# 编译器已经过优化,不会发出无法访问的代码。这称为死代码消除,它是C# 编译器执行的少数优化之一。

而且您不应该随意禁用警告。警告是问题的征兆。请看这个答案

于 2009-12-18T21:30:20.480 回答
24

首先,我同意你的观点,你需要摆脱所有警告。你得到的每一个小警告,通过解决问题来摆脱它。

在我继续重读之前,看起来像是咆哮,让我强调一下,使用这样的代码似乎没有任何性能损失。使用反射器检查代码后,看起来被“标记”为不可访问的代码实际上并未放入输出程序集中。

但是,它由编译器检查。仅此一项就足以成为无视我的咆哮的充分理由。

换句话说,摆脱该警告的最终效果就是,您摆脱了该警告。

另请注意,此答案是一种意见。你可能不同意我的观点,并想用它#pragma来掩盖警告信息,但至少对它的作用有一个明智的看法。如果你这样做,谁在乎我的想法。

话虽如此,您为什么要编写无法访问的代码?

您是否使用 consts 而不是“定义”?

警告不是错误。对您来说,这是一个注释,可以分析那段代码并确定您是否做对了。通常,你没有。在您的特定示例中,您故意编译将针对您的特定配置永远不会执行的代码。

为什么代码甚至在那里?它永远不会执行。

您是否对“常量”一词的实际含义感到困惑?常数意味着“这永远不会改变,如果你认为它会改变,它就不是常数”。这就是常数。它不会、也不能、也不应该改变。曾经。

编译器知道这一点,并会告诉你你有代码,由于一个常量,它永远不会被执行。这通常是一个错误。

这个常数会改变吗?如果是,它显然不是一个常量,而是取决于输出类型(Debug、Release)的东西,它是一个“#define”类型的东西,所以删除它,并改用那个机制。这使阅读您的代码的人更清楚地了解此特定代码所依赖的内容。如果您选择了未设置定义的输出模式,Visual Studio 还将有助于将代码灰显,因此代码将无法编译。这就是编译器定义要处理的内容。

另一方面,如果常量不会改变,无论出于何种原因,删除代码,你就不需要它了。

在任何情况下,都不要因为简单的修复而只为那段代码禁用该警告,这就像服用阿司匹林来“修复”你的背痛问题一样。这是一个短期的解决方案,但它掩盖了问题。而是解决根本问题。

为了完成这个答案,我想知道您的问题是否没有完全不同的解决方案。

通常,当我看到带有“检测到无法访问的代码”警告的代码时,它们属于以下类别之一:

  1. const对编译器的错误使用(在我看来)#define,你基本上对编译器说:“这段代码,请编译它,即使我知道它不会被使用。”。
  2. 错了,就像是完全错误的一样,就像一个 switch-case 有一个 case-block 包含一个 throw + a break。
  3. 以前迭代的剩余代码,您只是通过在某个点添加返回来使方法短路,而不是删除(甚至注释掉)后面的代码。
  4. 取决于某些配置设置的代码(即仅在调试构建期间有效)。

如果您拥有的代码不属于上述任何设置,那么您的常量会发生变化的具体情况是什么?知道这一点可能会给我们更好的方法来回答您关于如何处理它的问题。

于 2009-12-18T21:38:47.963 回答
22

那么使用预处理器语句呢?

#if ExecuteThis
    DoThis();
#endif

#if ExecuteThat
    DoThat();
#endif
于 2009-12-18T21:32:05.407 回答
11

嗯,#pragma但那是蹩脚的。我想知道是否ConditionalAttribute会更好 - 即

[Conditional("SOME_KEY")]
void DoThis() {...}
[Conditional("SOME_OTHER_KEY")]
void DoThis() {...}

现在,仅当或被定义为构建中的符号(“条件编译符号”)时才包含对/的调用。这也意味着您可以通过更改配置并在每个中定义不同的符号来在它们之间切换。DoThisDoThatSOME_KEYSOME_OTHER_KEY

于 2009-12-18T21:32:10.667 回答
3

这是一个技巧:

    bool FALSE = false;
    if (FALSE) { ... 

这将阻止警告。等待。我知道所有这些“你不应该使用它,为什么有没有执行的代码?”。答:因为在开发过程中您经常需要设置测试代码。最终你会摆脱它。重要的是代码在开发期间就在那里,但不是一直执行。

有时,出于调试目的,您想暂时删除代码执行。

有时您想暂时截断函数的执行。您可以使用它来避免警告:

...代码.. { bool TRUE = true; 如果(真)返回;} ...更多代码...

这些事情避免了警告。您可能会说,如果是暂时的,则应该保留警告。是的...但是再次...也许您不应该以这种方式检查它,但是暂时将警告发出去很有用,例如在花费一整天时调试复杂的碰撞代码。

所以,你可能会问,为什么这很重要?好吧,当我按 F4 转到第一个错误时,这些警告会变得非常烦人,而是先得到一些该死的 10 个警告,而我正在深入调试。

你说,使用#pragma。好吧,这将是一个好主意,除了我找不到在整个项目中全局执行此操作的方法.. 或者以一种可以与 Unity3D 一起使用的方式,这就是我在 C# 中编写的代码。哦,#include 会有多大用处。

没关系,使用 #if !嗯......是的......但有时它们不是你想要的。它们使代码混乱且不可读。您必须正确地将代码与它们括起来。将 if(false) 放在一个块的前面就容易多了……不需要分隔块,大括号就可以了。

我所做的是制作一个很好的全局可访问的 FALSE 和 TRUE 并在需要时使用它们来避免错误。

如果我想检查我是否真的在使用它们,我可以搜索所有引用,或者更粗略但同样有效地删除它们,从而被迫查看这个小技巧的每一次出现。

于 2014-09-28T19:25:48.697 回答
3

您在代码中声明了常量这一事实告诉我,您在每次发布时都在重新编译代码,您没有使用来自配置文件的“contants”。

所以解决方案很简单: - 从存储在配置文件中的值设置“常量”(标志) - 使用条件编译来控制编译的内容,如下所示:

#define ExecuteThis
//#define ExecuteThat

public void myFunction() {
#if ExecuteThis
    DoThis();
#endif
#if ExecuteThat
    DoThat();
#endif
}

然后,当您重新编译时,您只需取消注释正确的#define 语句即可编译正确的代码。还有一两种其他方法可以声明条件编译标志,但这只是为您提供了一个示例和开始的地方。

于 2009-12-18T21:36:17.460 回答
3

在不修改代码的情况下“摆脱它”的最快方法是使用

#pragma warning disable 0162

在您想要抑制警告的命名空间、类或方法上。

例如,这不会再抛出警告:

#pragma warning disable 0162
namespace ConsoleApplication4
{
  public class Program
  {
    public const bool something = false;

    static void Main(string[] args)
    {
        if (something) { Console.WriteLine(" Not something" ); }

    } 
 }

但是请注意,此命名空间内的 NO METHOD 将再次引发警告......而且......警告是有原因的(如果它发生在您没有计划它无法访问的情况下怎么办?)

我想更安全的方法是将变量写入配置文件,并在程序开始时从那里读取它们,这样您甚至不需要重新编译即可拥有不同的版本/发行版!只需更改应用程序文件并转到:D。

关于速度惩罚..是的..这样做会询问速度惩罚......与使用相比,const但除非你真的担心多花 1/100 毫秒......我会那样做。

于 2009-12-18T21:44:55.727 回答
2

最简单的方法是停止编写无法访问的代码:D #DontDoThat

于 2009-12-18T21:34:59.763 回答