【问题标题】:Suppressing "is never used" and "is never assigned to" warnings in C#在 C# 中抑制“从未使用”和“从未分配给”警告
【发布时间】:2011-04-18 18:30:31
【问题描述】:

我在 C# 项目中有一个 HTTPSystemDefinitions.cs 文件,它基本上描述了托管代码使用的旧 Windows ISAPI。

这包括与 ISAPI 相关的完整结构集,而不是全部或由代码使用。在编译时,这些结构的所有字段成员都会导致如下警告:-

警告字段 'UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.SetHeader' 从未分配给,并且始终具有其默认值 null

警告从未使用过“UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.HttpStatus”字段

可以用#pragma warning disable 禁用这些吗?如果是这样,相应的错误编号是多少?如果没有,我还能做些什么吗?请记住,我只对此文件执行此操作,重要的是我会看到来自其他文件的此类警告。

编辑

示例结构:-

struct HTTP_FILTER_PREPROC_HEADERS
{
    //
    //  For SF_NOTIFY_PREPROC_HEADERS, retrieves the specified header value.
    //  Header names should include the trailing ':'.  The special values
    //  'method', 'url' and 'version' can be used to retrieve the individual
    //  portions of the request line
    //

    internal GetHeaderDelegate GetHeader;
    internal SetHeaderDelegate SetHeader;
    internal AddHeaderDelegate AddHeader;

    UInt32  HttpStatus;               // New in 4.0, status for SEND_RESPONSE
    UInt32  dwReserved;               // New in 4.0
}

【问题讨论】:

  • 你能显示这些字段的声明,或者更确切地说,它们所在的结构吗? IE。举个例子。
  • 如果这些是互操作定义,那么通常你会输入[StructLayout(LayoutKind.Sequential)] 以确保内存布局是正确的(在当前的实现中,即使没有这个属性,但AFAIK不能保证)。如果我没记错的话,C# 编译器会检测到此属性的存在并自动抑制这些警告,因为它知道字段必须存在才能进行互操作。 (我可能错了,因此发布为评论而不是答案)。
  • @Greg:这是有用的信息,我将进行调查我宁愿不生成警告而不是抑制它们。
  • +1 用于使用StructLayout。这似乎比隐藏警告本身更干净。
  • @GregBeech 你是对的!这仍然适用于 VS2017 上的 .NET Standard 项目。

标签: c# visual-studio suppress-warnings


【解决方案1】:

是的,这些可以被抑制。

通常,我反对抑制警告,但在这种情况下,用于互操作的结构绝对需要存在一些字段,即使您从未打算(或不能)使用它们,所以在这种情况下,我认为它应该是合理的。

通常,要抑制这两个警告,您需要修复有问题的代码。第一个(“...从未使用过”)通常是早期版本代码中残留的代码气味。也许代码被删除了,但是字段被留下了。

第二个通常是错误使用字段的代码异味。例如,您可能会错误地将属性的新值写回属性本身,而不是写入支持字段。


要禁止“从未使用字段 XYZ”的警告,请执行以下操作:

#pragma warning disable 0169
... field declaration
#pragma warning restore 0169

要禁止“字段 XYZ 从未分配给,并且将始终具有其默认值 XX”的警告,请执行以下操作:

#pragma warning disable 0649
... field declaration
#pragma warning restore 0649

要自己查找此类警告编号(即我怎么知道使用 0169 和 0649),您可以这样做:

  • 正常编译代码,这会在 Visual Studio 的错误列表中添加一些警告
  • 切换到“输出”窗口和“构建”输出,并寻找相同的警告
  • 复制相关消息中的 4 位警告代码,代码应如下所示:

    C:\Dev\VS.NET\ConsoleApplication19\ConsoleApplication19\Program.cs(10,28): 警告 CS0649:字段 'ConsoleApplication19.Program.dwReserved' 永远不会 分配给,并将始终具有其默认值 0


警告:根据@Jon Hanna 的评论,也许一些警告是为了这个,为了这个问题和答案的未来发现者。

  • 首先,抑制警告的行为类似于为头痛吞服药丸。当然,有时这可能是正确的做法,但这并不是一个包罗万象的解决方案。有时,头痛是您不应该掩盖的真实症状,警告也是如此。始终最好尝试通过修复警告的原因来处理警告,而不是盲目地从构建输出中删除它们。
  • 话虽如此,如果您需要取消警告,请按照我上面列出的模式。第一个代码行#pragma warning disable XYZK 禁用警告该文件的其余部分,或者至少在找到相应的#pragma warning restore XYZK 之前。尽量减少禁用这些警告的行数。上面的模式仅禁用一行警告。
  • 另外,正如 Jon 所提到的,评论一下您为什么这样做是个好主意。无故禁用警告绝对是一种代码异味,并且注释会阻止未来的维护者花时间思考您为什么这样做,甚至删除它并尝试修复警告。

【讨论】:

  • 我建议进一步回答上面的答案,禁用的范围尽可能小(以避免在有用的地方禁用它)并始终伴随禁用注释为为什么你要禁用,例如//exists for interop 在这种情况下。
  • 非常感谢。 VS 在错误列表窗口中没有包含这些数字的列,这是一个奇怪的选择。
  • 正如 Jon 所说,评论“为什么”非常重要。此外,我通常将警告消息的至少部分文本添加到评论中,例如// 禁止“从未分配给...”警告。让未来的维护者免去查看警告代码的烦恼——毕竟,它可能是你!
  • 它不是很明显,但是您可以通过 CTRL+F 在输出窗口中使用查找,输入“警告”,单击“查找全部”并快速获取每个警告,并显示警告编号。也就是说,根据 Greg Beech 对该问题的评论,[StructLayout(LayoutKind.Sequential)] 属性可以更好地处理互操作。
  • 评论说对于 Unity3D 用户,私有字段的警告编号是 0414,局部变量的警告编号是 0219,而不是 169(它会引发无法恢复警告的警告)。
【解决方案2】:

我让 VS 为 System.ComponentModel.INotifyPropertyChanged 生成实现框架,事件被实现为触发 CS0067 警告的字段。

作为已接受答案中给出的解决方案的替代方案我将字段转换为属性并且警告消失了

这是有道理的,因为属性声明语法糖被编译成一个字段加上引用该字段的 getter 和/或 setter 方法(在我的例子中是添加/删除)。这满足了编译器并且不会引发警告:

struct HTTP_FILTER_PREPROC_HEADERS
{
    //
    //  For SF_NOTIFY_PREPROC_HEADERS, retrieves the specified header value.
    //  Header names should include the trailing ':'.  The special values
    //  'method', 'url' and 'version' can be used to retrieve the individual
    //  portions of the request line
    //

    internal GetHeaderDelegate GetHeader {get;set;}
    internal SetHeaderDelegate SetHeader { get; set; }
    internal AddHeaderDelegate AddHeader { get; set; }

    UInt32 HttpStatus { get; set; }               // New in 4.0, status for SEND_RESPONSE
    UInt32 dwReserved { get; set; }               // New in 4.0
}

【讨论】:

  • 您的解决方案比禁用警告要优雅得多,但它可能会干扰某些仅限字段的属性,例如MarshalAsAttribute.
  • 信息:在这种情况下生成的实际私有字段可能具有“奇怪”的名称,例如<GetHeader>k__BackingField,具体取决于所使用的 C# 编译器的实现细节。
【解决方案3】:

解决这些警告的另一个“解决方案”是创建结构public。那时不会发出警告,因为编译器无法知道这些字段是否在程序集之外被使用(分配)。

也就是说,“互操作”组件通常不应该是公开的,而是internalprivate

【讨论】:

  • 很好,这确实隐藏了警告......但是将这样的struct 设置为public 比我们试图掩盖的警告更可能是一个错误。 (您可能不应该不必要地公开用于内部实现的类型,并且具有公共字段的类型可能不属于公共 API)。只是为了加强您的建议,即此类类型应该是“internalprivate”;-)。
  • 非常感谢 - 这正是我所需要的。我正在使用JsonConvert.DeserializeObject,并且我正在反序列化为一个公共类,该类只公开了所有属性,以便我知道将返回什么。只需将其设置为包含所有公共字符串的空公共类就是不错的短代码,现在不再有警告。也许使用动态类会更好,因为您不必明确说明数组中的内容,但我认为这对于希望使用该对象的任何人来说都是一个很好的参考。
【解决方案4】:

C/C++ 用户有(void)var; 来抑制未使用的变量警告。 我刚刚发现您还可以使用位运算符在 C# 中抑制未使用的变量警告:

        uint test1 = 12345;
        test1 |= 0; // test1 is still 12345

        bool test2 = true;
        test2 &= false; // test2 is now false

在 VS2010 C# 4.0 和 Mono 2.10 编译器中,这两个表达式都不会产生未使用的变量警告。

【讨论】:

  • 适用于uint,但不适用于其他类型,如Exception。你知道一个相当于 C/C++ var; 的通用技巧吗?
  • @manuell 你好,来自未来!您可以将error.ToString(); 用于Exception 类型的变量
  • 从现在开始谢谢。这个技巧确实会在运行时添加真正的代码,对吧?
  • _ = test1; 看起来更好。
  • @Pang 添加您自己的答案,以便我们投票。当我回答时,未使用的抑制器已不在该语言中
猜你喜欢
  • 2013-01-23
  • 2012-08-29
  • 1970-01-01
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 1970-01-01
相关资源
最近更新 更多