为啥 FxCop 将 GC.KeepAlive() 标记为违规?

Posted

技术标签:

【中文标题】为啥 FxCop 将 GC.KeepAlive() 标记为违规?【英文标题】:Why does FxCop flag GC.KeepAlive() as a violation?为什么 FxCop 将 GC.KeepAlive() 标记为违规? 【发布时间】:2011-01-11 19:45:14 【问题描述】:

GC.KeepAlive() 有什么不好以至于 FxCop 将其标记为违规?

【问题讨论】:

@HansPassant:比 API 更智能意味着什么?为什么我必须超越某些技术才能调用 API 函数that has a well-understood purpose (described here by Eric Lippert)?我对你的暗示感到不舒服,即仅仅问一个(合理的)问题就表明缺乏智慧。 你又在向信使开枪了。我没有编写 FxCop,也不对其设计师所做的选择负责。 @HansPassant:我完全是指你上面的评论,没有别的。 【参考方案1】:

可能是因为调用它被认为是不好的做法,就像调用 GC.Collect 通常是一个坏主意一样——它通常会对收集器产生负面影响和/或可能表明您的设计存在缺陷结束。

但是,如果您需要调用该方法,您应该能够重新配置 FxCop 以不考虑对该方法的调用。毕竟,这样做是有正当理由的。

【讨论】:

不安全的代码不是“通常不好的做法”,并且各种框架类(例如,WPF 的WriteableBitmap)公开了非托管指针。如果指针是我唯一保留的引用,我最好使用GC.KeepAlive 否则会发生不好的事情。【参考方案2】:

并不是说 GC.KeepAlive 特别糟糕,而是如果您转换为 SafeHandle 用法,则没有必要,而且您真的,真的应该转换为 SafeHandle 用法。如果您不确定原因,不妨考虑查看http://blogs.msdn.com/b/bclteam/archive/2005/03/16/396900.aspx 和http://blogs.msdn.com/b/bclteam/archive/2006/06/23/644343.aspx。

【讨论】:

在某些情况下,我认为 SafeHandle 不能很好地工作。例如,从长期存在的对象接收事件的对象将无法有效地完成;一种解决方案是让对象的用户持有对可终结包装器的引用,而后者又持有对主对象的引用。包装器的完成会触发对象的清理。在这种情况下,封装的调用将需要 GC.KeepAlive() 并且我不确定 SafeHandle 将如何避免这种情况。 听起来您提出的方法会触及终结器中的托管对象。由于msdn.microsoft.com/en-us/library/ddae83kx.aspx 中描述的原因,这不是一个好主意。在订阅长期发布者的事件时,还有其他方法可用于避免资源泄漏。 这并不总是可行的。您忘记了第二种情况:非互操作的纯 C# 但不安全的代码,例如获取位图的后台缓冲区并直接从中读取。这可以保证KeepAlive @romkyns:问题不是关于 KeepAlive 的一般用法,而是关于 FxCop 规则 RemoveCallsToGCKeepAlive,它专门用于检测可能应该使用 SafeHandle 代替终结器的潜在情况。

以上是关于为啥 FxCop 将 GC.KeepAlive() 标记为违规?的主要内容,如果未能解决你的问题,请参考以下文章

我应该使用 FxCop,为啥?

FxCop - CA1034 错误 - 为啥?

为啥我会收到来自 FxCop 的 InitializeReferenceTypeStaticFieldsInline 警告?

为啥 FxCop 给我一个“DoNotCastUnnecessarily”警告?

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

为啥 FxCop 会在此 C# 代码中发出有关溢出 (CA2233) 的警告?