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

C# 使用链式构造函数避免代码分析CA2000警告?,c#,visual-studio-2010,code-analysis,fxcop,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(); } } 有点罗嗦,但它有效,而且有意义。但是如何将该模式应用于链式构造函数,如下

避免关于未处理局部变量的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似乎需要很多),但如果有实际的方法来消除问题,我更愿意这样做。

我无法在接受IDataRepository参数的构造函数上重新设置CA2000冲突。考虑到这一点,再加上您对两个构造函数使用相同的“默认值”,可以避免示例场景中出现CA2000问题的最简单更改是:

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

public HomeController()
    : this(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;
    }
}
公共家庭控制器(IDataRepository db)
:此(()=>db,false)
{
if(db==null)
{
抛出新的ArgumentNullException(“db”);
}
}
公共家庭控制器()
:此(()=>newsqldatarepository(),true)
{
}
专用家庭控制器(Func repositoryRetriever,bool disposeOnFailure)
{
IDataRepository repository=repositoryRetriever.Invoke();
尝试
{
this.repo=存储库;
}
抓住
{
如果(失败)
{
repository.Dispose();
}
投掷;
}
}
就我个人而言,我认为上面的攻击相当令人讨厌,特别是考虑到它涉及到增加代码复杂性和运行时异常的可能性,以避免一开始并不严重的潜在问题。我的建议是忽略此类潜在的CA2000违规行为,除非以下两项都是正确的:

  • 在对象的实例化和将其分配给字段的方法结束之间,很有可能出现非崩溃异常
  • 未能处理孤立实例的后果相当严重(例如:使文件处于锁定状态)

  • repositoryRetriever
    是否应该在
    try
    块中调用?@ChrisWue:不,不需要这样做。在将一次性值分配给目标变量之前,您无法处理它,因为您没有对它的引用。IMO,这是一个CA错误。