为啥 FxCop 坚持使用 IDisposable 作为结构

Posted

技术标签:

【中文标题】为啥 FxCop 坚持使用 IDisposable 作为结构【英文标题】:Why does FxCop insist on IDisposable for a struct为什么 FxCop 坚持使用 IDisposable 作为结构 【发布时间】:2012-11-07 19:59:27 【问题描述】:

我的一个项目中有类似于以下的代码:

internal enum ArtworkType

    Undefined = 0,
    Bmp = 1,
    Gif = 2,
    Jpeg = 3,
    Png = 4


[StructLayout(LayoutKind.Sequential)]
internal struct TagArtwork

    internal IntPtr data;
    internal int size;
    internal ArtworkType type;

当我在这段代码上运行 FxCop 时,我遇到了警告 CA1049。该结构用于与本机代码库的互操作性,因此几乎必须拥有这种布局。为什么 FxCop 让我对这个结构感到悲伤?我在同一个源文件中有其他结构,它们也有 IntPtr 成员,但 FxCop 不会抱怨这些。

例如,以下代码不会触发相同的警告:

internal enum ItemType

    Implicit = 0,
    Utf8 = 1,
    Utf16 = 2,
    Sjis = 3,
    html = 6,
    Xml = 7,
    Uuid = 8,
    Isrc = 9,
    Mi3p = 10,
    Gif = 12,
    Jpeg = 13,
    Png = 14,
    Url = 15,
    Duration = 16,
    DateTime = 17,
    Genres = 18,
    Integer = 21,
    Riaa_pa = 24,
    Upc = 25,
    Bmp = 27,
    Undefined = 255


[StructLayout(LayoutKind.Sequential)]
internal struct MP4ItmfData

    internal byte typeSetIdentifier;
    internal ItemType typeCode;
    internal int locale;
    internal IntPtr value;
    internal int valueSize;

我想我可以在结构上实现IDisposable,但这似乎是错误的。同样,我可以简单地抑制警告,但目前,我想了解触发警告的这个特定结构是什么,当它与我在同一个源文件中的其他七个结构没有太大不同时。或者,我很乐意接受解释为什么其他结构触发此警告。

【问题讨论】:

只是禁止警告,除非你是分配非托管句柄的人,在这种情况下你应该实现 IDisposable。 我意识到我可以简单地抑制警告,但我想了解是什么让 this 结构如此特别。我将编辑问题以明确表示我不想在这种情况下禁止显示警告。 您能否发布另一个同样具有 IntPtr 且不会触发 FxCop 警告的结构的代码? @Scott 完成最新编辑。 【参考方案1】:

只要您的托管类型包含它认为是“本机”类型的成员,Code Anylsis 引擎就会生成此警告。要成为原生类型,该字段必须:

成为IntPtrUIntPtrHandleRef 不是static 实际上是从本机代码中赋值的

我很确定这第三个项目符号可能是您的各种结构之间的区别。分析引擎(基于对 dotPeek 的快速阅读)只有在实际发现您的 IntPtr 的实例是从本机代码分配时才会触发警告。我还没有找到它所认为的“来自本机代码的赋值”的确切内容,但不管是什么,我最好的猜测是你们中只有一个不同的struct 类型正在触发这部分规则。

请注意,这是基于读取 VS2010 附带的代码分析引擎的当前实现的实际代码。这绝对是不是记录在案的规则行为,而可能是减少误报的特定优化。您不应假设当前“通过”此规则的代码(例如,因为它从未从本机代码分配)将始终这样做,因为 MS 可以随时更改实现细节。

正如我在评论中提到的,在这种情况下,隐藏消息是完全合法的回应;这不是不应禁止的 FxCop 规则之一。该规则是非常特定于上下文的,并且仅在您分配您自己的本机资源时适用。如果您只是在 C# 和非托管代码之间来回传递结构,那么您很可能只是取消警告并继续前进。

【讨论】:

就是这样,实际上是从本机代码分配的。我忘记阅读哪些文档页面,这些项目符号的布局位置? 他们不是。我在代码分析程序集上运行了 dotPeek 并对其进行了跟踪。我应该在回答中指出这一点。 警告将应用于结构似乎很奇怪,因为结构不可能真正“拥有”任何东西。分析引擎记录包含此类类型的结构是有意义的,并建议任何包含这些结构类型字段的类都应实现IDisposable,但具有结构类型包括@987654328 的非平凡实现@ 似乎是一个非常严厉的反模式。【参考方案2】:

在您链接的文章中已经清楚地说明了这一点:

此规则假定 IntPtr、UIntPtr 和 HandleRef 字段存储指向非托管资源的指针。分配非托管资源的类型应该实现 IDisposable 以让调用者按需释放这些资源并缩短持有资源的对象的生命周期。

因此,仅 IntPtr 在结构中的简单外观就足以触发警告。在您确认您真的没有忘记释放本机资源后,在结构上应用 [SuppressMessage] 属性,不必再次查看此消息。

【讨论】:

但这正是我的观点。在同一个项目中,我实际上有七个其他结构,其中五个还包含IntPtr 成员。它们都不会触发相同的警告。是的,我阅读了文档;不,我不明白一个结构如何触发警告,但其他结构不会。

以上是关于为啥 FxCop 坚持使用 IDisposable 作为结构的主要内容,如果未能解决你的问题,请参考以下文章

本地使用的 IDisposable 是不是有 FxCop 规则?

FxCop(/VS2010 代码分析),可以将方法结果标记为 IDisposable 的“现在调用者责任”吗?

FXCop:“拥有一次性字段的类型应该是一次性的”

我应该使用 FxCop,为啥?

为啥我在 IDisposable 类中获得带有私有成员 IDisposable 的 CA2000?

PetaPoco.Database 实现了 IDisposable,那么为啥大多数示例没有“使用”语句呢?