使用链式构造函数避免代码分析CA2000警告?

时间:2011-07-19 17:14:28

标签: c# visual-studio-2010 code-analysis fxcop

避免CA2000警告未处理的本地人的正常模式是使用临时变量,如果出现任何问题就会被处置,例如:

Foo f = null;
try
{
    f = new Foo();
    Foo result = f;
    f = null;
    return result;
}
finally
{
    if (f != null)
    {
        f.Dispose();
    }
}

有点冗长,但它有效,而且有意义。但是如何将这种模式应用于链式构造函数,如下所示:

public HomeController ( IDataRepository db )
{
    this.repo = db ?? new SqlDataRepository();
}

public HomeController ( )
    : this(new SqlDataRepository())
{
}

此代码抛出两个CA2000警告,每个构造函数一个。第一个我可以摆脱使用临时变量模式。这很烦人,因为在构建之后,但是在它被分配到成员字段之前,本地没有任何方式让它超出范围,之后会被清除。所以我不知道CA的问题是什么,但至少我知道如何解决它。

但是,据我所知,没有任何其他方法可以编写第二个构造函数调用来引入try / finally。分配给的字段是只读的,因此必须在构造函数中设置。并且C#不会让你在构造函数体之前的任何地方调用链式构造函数。而且,在这两个中,第二个警告实际上是更合法的一个 - 对链式构造函数的调用(理论上,如果它做了任何实际工作)抛出一个异常并使新构造的参数不被暴露。

当然,我总是可以压制这个消息(CA2000似乎需要很多),但如果有一种实际的方法可以消除这个问题,我宁愿这样做。

1 个答案:

答案 0 :(得分:2)

我无法在带有IDataRepository参数的构造函数上重现CA2000违规。鉴于此,以及对两个构造函数使用相同的“默认”这一事实,最简单的更改将避免样本方案的CA2000问题:

public HomeController(IDataRepository db)
{
    this.repo = db ?? new SqlDataRepository();
}

public HomeController()
    : this(null)
{
}

显然,如果您的第一个构造函数不接受null参数值,这将无法正常工作。如果是这种情况,并且您完全同意只在一个地方设置相应字段的想法,您仍然可以选择避免使用CA2000,例如调用稍微更智能的私有构造函数。 e.g:

public HomeController(IDataRepository db)
    : this(() => db, false)
{
    if (db == null)
    {
        throw new ArgumentNullException("db");
    }
}

public HomeController()
    : this(() => new SqlDataRepository(), true)
{
}

private HomeController(Func<IDataRepository> repositoryRetriever, bool disposeOnFailure)
{
    IDataRepository repository = repositoryRetriever.Invoke();
    try
    {
        this.repo = repository;
    }
    catch
    {
        if (disposeOnFailure)
        {
            repository.Dispose();
        }

        throw;
    }
}

就我个人而言,我认为以上是非常讨厌的黑客,特别是考虑到它涉及增加代码复杂性和运行时异常的机会,以避免一开始就不是很严重的潜在问题。我的建议是简单地忽略此类潜在的CA2000违规,除非以下两种情况都成立:

  1. 在对象的实例化和将其分配给字段的方法的结尾之间存在非崩溃异常的可能性。
  2. 未能处理孤立实例的后果相当严重(例如:将文件锁定)。