禁止在C#中使用“从不使用”和“从不分配给”警告


107

我在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
}

您可以显示这些字段的声明,还是显示它们所在的结构?即。举个例子。
Lasse V. Karlsen

11
如果这些是互操作定义,那么通常可以[StructLayout(LayoutKind.Sequential)]确保内存布局正确(在当前实现中,甚至没有此属性也可以,但是不能保证AFAIK)。如果我没记错的话,C#编译器会检测到此属性的存在,并会自动禁止显示这些警告,因为它知道必须存在用于互操作的字段。(对此我可能是错的,因此将其发布为评论而不是答案)。
格雷格·比奇

@Greg:这是有用的信息,我将调查它,我宁愿不生成警告而不是抑制它们。
AnthonyWJones

1
+1以使用StructLayout。似乎比抑制警告本身还干净。
Deanna 2014年

@GregBeech你是对的!这仍然适用于VS2017上的.NET Standard项目。
zwcloud

Answers:


195

是的,这些可以被抑制。

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

通常,要排除这两个警告,您将修复有问题的代码。第一个(“ ...永不使用”)通常是早期版本代码遗留下来的代码气味。也许代码已删除,但字段留在后面。

第二个通常是针对错误使用字段的代码气味。例如,您可能会错误地将属性的新值写回到属性本身,而不要写入后备字段。


要禁止显示“ 从不使用字段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):警告CS 0649:从未将字段'ConsoleApplication19.Program.dwReserved'分配给该字段,并且其默认值始终为0


警告:根据@Jon Hanna的评论,可能为此发出了一些警告,以供将来查找此问题和答案的人使用。

  • 首先,也是最重要的是,抑制警告的行为类似于吞咽头痛药。当然,有时候这样做可能是正确的事,但这不是万能的解决方案。有时候,头痛是您不应该掩盖的真实症状,与警告一样。始终最好尝试通过修正警告原因来处理警告,而不是仅仅从构建输出中盲目删除警告。
  • 话虽如此,如果您需要取消警告,请遵循我上面列出的模式。第一行代码#pragma warning disable XYZK禁用该文件其余部分的警告,或者至少直到#pragma warning restore XYZK找到相应的警告为止。最小化您禁用这些警告的行数。上面的模式仅对一行禁用警告。
  • 而且,正如乔恩(Jon)所提到的,评论为什么这样做是一个好主意。毫无疑问,禁用警告绝对是一种代码气味,注释会阻止将来的维护人员花时间去思考为什么这样做,甚至删除它并尝试修复警告。

9
我建议对上述答案做进一步的说明,禁用的范围应尽可能小(以避免在有用的地方禁用它),并始终在禁用时附带注释,说明您为何禁用,例如//exists for interop在这个案例。
乔恩·汉娜

非常感谢。VS在“错误列表”窗口中不包含这些数字的列是一个奇怪的选择。
AnthonyWJones

2
正如乔恩所说,评论“为什么”非常重要。另外,我通常将警告消息的文本的至少一部分添加到注释中,例如//禁止“从不分配给...”警告。避免将来的维护人员不得不查找警告代码的烦恼-毕竟,可能是您!
汤姆·贝希尔

1
它不是立即显而易见的,但是您可以通过CTRL + F在“输出”窗口中使用“查找”,键入“警告”,单击“查找全部”,并迅速获得所有警告,并显示警告编号。也就是说[StructLayout(LayoutKind.Sequential)],根据Greg Beech对问题的评论,该属性可以更好地处理互操作。
Ryan Buddicom 2014年

2
注释说,对于Unity3D用户而言,对于私有字段,警告编号是0414,对于局部变量,警告编号是0219,而不是169(这将引发有关无法还原警告的警告)。
Draco18s不再信任SE SE

14

解决这些警告的另一个“解决方案”是制作struct public。然后不会发出警告,因为编译器无法知道是否在程序集外部使用(分配)了这些字段。

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


2
很好,这确实隐藏了警告……但是将a设置structpublica比我们试图掩盖的警告更可能是一个错误。(您可能不必不必要地公开用于内部实现的类型,具有公共字段的类型可能不属于公共API)。只是为了加强您的建议,即此类类型应为“ internalprivate” ;-)。
binki 2014年

非常感谢-这就是我所需要的。我正在使用JsonConvert.DeserializeObject并且正在反序列化为一个公开类,该类只公开了所有属性,以便我知道将返回什么。只需将其设置为一个空类,并包含所有公共字符串的公共类就是不错的短代码,现在不再有警告。也许使用动态类会更好,因为您不必显式声明数组中的内容,但是我认为这对于希望使用该对象的任何人都是不错的参考。
user1274820

6

我得到了VS来为其生成实现框架,System.ComponentModel.INotifyPropertyChanged并且这些事件被实现为触发CS0067警告的字段。

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

这是有道理的,因为属性声明语法糖被编译成一个字段以及引用该字段的getter和/或setter方法(在我的情况下为add / remove)。这满足了编译器,并且不会引发警告:

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。
HuBeZa 2012年

1
信息:在这种情况下生成的实际私有字段可能具有“奇怪的”名称,例如 <GetHeader>k__BackingField,这取决于所使用的C#编译器的实现细节。
Jeppe Stig Nielsen

1

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编译器中,这两个表达式都不会产生未使用的变量警告。


4
适用于uint,但不适用于其他类型Exception。您知道等效于C / C ++的通用技巧var;吗?
manuell,2015年

1
@manuell未来的你好!您可以将error.ToString();变量用于类型Exception
Sv443

从现在开始。这个技巧确实在运行时添加了真实的代码,对吗?
manuell
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.