C# 告诉FxCop另一个方法正在调用dispose

C# 告诉FxCop另一个方法正在调用dispose,c#,idisposable,fxcop,C#,Idisposable,Fxcop,通常,在处置私有成员时,可以执行以下操作: public void Dispose() { var localInst = this.privateMember; if (localInst != null) { localInst.Dispose(); } } 本地分配的目的是避免出现争用情况,在这种情况下,另一个线程可能会在null检查后将私有成员分配为null。在本例中,我不关心是否对实例调用了两次Dispose 我一直使用这种模式,因此我编写了一

通常,在处置私有成员时,可以执行以下操作:

public void Dispose() {
    var localInst = this.privateMember;
    if (localInst != null) {
        localInst.Dispose();
    }
}
本地分配的目的是避免出现争用情况,在这种情况下,另一个线程可能会在null检查后将私有成员分配为null。在本例中,我不关心是否对实例调用了两次
Dispose

我一直使用这种模式,因此我编写了一个扩展方法来实现这一点:

public static void SafeDispose(this IDisposable disposable)
{
    if (disposable != null)
    {
        // We also know disposable cannot be null here, 
        // even if the original reference is null.
        disposable.Dispose();
    }
}
现在在我的课堂上,我可以做到:

public void Dispose() {
    this.privateMember.SafeDispose();
}
问题是,FxCop不知道我在做这件事,它在任何情况下都会给我警告


我不想关闭这个规则,也不想压制每一个案例。有没有办法向FxCop提示,就其而言,此方法相当于
Dispose

我绝不是FxCop专家,但关于使用SuppressMessage是否回答了这个问题?我不知道用SuppressMessage属性修饰SafeDispose方法是否会导致FxCop在分析调用它的方法时抑制该消息,但似乎值得一试

不要相信下面的语法,但类似于:

[SuppressMessage("Microsoft.Design", "CA2000:Dispose objects before losing scope", Justification = "We just log the exception and return an HTTP code")]
public static void SafeDispose(this IDisposable disposable)

简短的回答是:无法暗示该对象正在其他地方处置。

一点反射器的窥视(或打点窥视,或其他什么)解释了原因

FxCop位于
C:\ProgramFiles(x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop
中。(根据OS/VS版本组合进行相应调整。)规则位于
Rules
子目录中

在主
FxCop
文件夹中打开

  • Microsoft.VisualStudio.CodeAnalysis.dll
  • Microsoft.VisualStudio.CodeAnalysis.Phoenix.dll
  • phx.dll
规则
文件夹
中,打开
数据流规则.dll

DataflowRules.dll
中查找
Phoenix.codesanalysis.DataflowRules.DisposeObjectsBeforeLosingScope
。这就是进行评估的实际类

查看其中的代码,您可以看到与您的问题相关的两件有趣的事情

  • 它使用一个名为
    SharedNeedsDisposedAnalysis
    的共享服务
  • 源自
    FunctionBodyRule
  • 第一项很有意思,因为SharedNeedsDisposedAnalysis决定了哪些符号需要调用
    Dispose()
    。非常彻底,通过对代码进行“漫游”来确定需要处理哪些符号以及实际处理哪些符号。然后,它会保存一张这些东西的表格,供以后使用

    第二项很有趣,因为
    FunctionBodyRule
    规则评估单个函数的主体。还有其他规则类型,如
    FunctionCallRule
    ,用于评估函数调用成员之类的内容(例如,
    providedcorrectargumentstoformatingmethods

    关键是,在
    SharedNeedsDisposedAnalysiss
    服务中可能出现的“未命中”和
    FunctionBodyRule
    没有超出函数体的限制之间,它只是没有捕获您的扩展。

    这也是像
    guard.country(arg)
    这样的“guard functions”在使用参数之前从未被视为验证参数的原因-FxCop仍然会告诉您检查参数是否为null,即使“guard function”正在执行此操作

    你基本上有两个选择

  • 排除问题或关闭规则。它不可能满足您的要求
  • 创建可理解扩展方法的自定义/派生规则。使用自定义规则代替默认规则

  • 在我自己写了自定义FxCop规则之后,我会告诉你我找到了它。。。不平凡。如果你真的走这条路,虽然世界上推荐使用新的Phoenix引擎规则样式(当前的
    DisposeObjectsBeforeLosingScope
    使用这种样式),但我发现更容易理解旧的/标准的FxCopSdk规则(请参阅主FxCop文件夹中的
    FxCopSdk.dll
    )。反射器将是一个巨大的帮助,以找出如何做到这一点,因为它有几乎零文件。查看
    规则
    文件夹中的其他程序集,以查看这些程序集的示例。

    出于Travis概述的所有原因,此代码分析规则是有问题的。它似乎在排队退出任何“新”操作,除非dispose调用关闭,否则将触发CA2000

    与其使用new,不如在正文中使用以下内容调用方法:

    MyDisposableClass result;
    MyDisposableClass temp = null;
    try
    {
      temp = new MyDisposableClass();
      //do any initialization here
      result = temp;
      temp = null;
    }
    finally
    {
      if (temp != null) temp.Dispose();
    }
    return result;
    
    这样做的目的是消除初始化导致对象无法访问以进行处理的任何可能性。在您的情况下,当您“新建”privatemember时,您将在类似于上述方法的方法中执行此操作。使用此模式后,您当然仍然要负责正确的处理,并且您的扩展方法是推广空检查的一个很好的方法

    我发现,您可以避免使用CA2000,同时仍然可以传递IDisPobles并使用它们做您想做的事情——只要您使用上述方法正确地更新它们。试试看,让我知道它是否适合你。祝你好运,好问题


    此规则(包括此规则)的其他修复程序如下所示:

    您的示例显示
    this.privatember.Dispose()
    。您的代码是否实际显示了
    this.privateMember.SafeDispose()
    ?实际上,有一种机制可以通过CA1062识别保护函数:使用名为ValidatedNotNullAttribute的属性进行装饰。不幸的是,处置规则没有类似的机制。谢谢特拉维斯!你知道编写自定义规则的好指南吗?我已经将fxcop作为构建的一部分运行,我希望确保