简体   繁体   English

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

[英]Avoiding code analysis CA2000 warning with chained constructors?

The normal pattern for avoiding the CA2000 warning about non-disposed locals is to use a temp variable that gets disposed if anything goes wrong, like:避免 CA2000 警告关于 non-disposed locals 的正常模式是使用一个临时变量,如果出现任何问题,该变量就会被释放,例如:

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

A bit verbose, but it works, and it makes sense.有点冗长,但它有效,而且很有意义。 But how does one apply that pattern to chained constructors, like this:但是如何将该模式应用于链式构造函数,如下所示:

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

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

This code is throwing up two CA2000 warnings, one per constructor.此代码抛出两个 CA2000 警告,每个构造函数一个。 The first one I can get rid of using the temp variable pattern.第一个我可以摆脱使用临时变量模式。 It's pretty annoying, since there doesn't see to be any way for the local to go out of scope after it's constructed but before it gets assigned to the member field, which gets cleaned up later.这很烦人,因为在 scope 构建之后但在它被分配给成员字段之前,go 的本地没有任何方法,该字段稍后会被清理。 So I dunno what CA's problem is, but at least I know what to do to fix it.所以我不知道 CA 的问题是什么,但至少我知道如何解决它。

But, as far as I can figure out, there isn't any alternative way to write the second constructor call to introduce a try/finally.但是,据我所知,没有任何替代方法可以编写第二个构造函数调用来引入 try/finally。 The field being assigned to is read-only, so it must be set in a constructor.分配给的字段是只读的,因此必须在构造函数中设置。 And C# won't let you call chained constructors anywhere but immediately before the constructor body.并且 C# 不会让您在任何地方调用链式构造函数,而是紧接在构造函数主体之前。 And, of the two, the second warning is actually the more legitimate one -- the call to the chained constructor could (in theory, if it did any actual work) throw an exception and leave the newly constructed parameter undisposed.而且,在这两个警告中,第二个警告实际上是更合理的一个——对链式构造函数的调用可能(理论上,如果它确实做了任何实际工作)会引发异常,并使新构造的参数不被处理。

Of course, I can always just suppress this message (which CA2000 seems to need a lot of), but if there's an actual way to eliminate the problem I'd prefer to do that.当然,我总是可以直接压制这条消息(CA2000 似乎需要很多),但如果有一种实际的方法可以消除这个问题,我更愿意这样做。

I cannot repro the CA2000 violation on the constructor that takes a IDataRepository argument.我无法在采用 IDataRepository 参数的构造函数上重现 CA2000 违规。 Given this, along with the fact that you use the same "default" for both constructors, the simplest change that would avoid CA2000 problems for the sample scenario is:鉴于此,以及您对两个构造函数使用相同的“默认值”这一事实,在示例场景中避免 CA2000 问题的最简单更改是:

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

public HomeController()
    : this(null)
{
}

Obviously, this wouldn't work too well if your first constructor did not accept a null parameter value.显然,如果您的第一个构造函数不接受 null 参数值,这将无法正常工作。 If this were the case and you're absolutely married to the idea of setting the corresponding field in only one place, you would still have options for avoiding CA2000, such invoking a slightly smarter private constructor.如果是这种情况,并且您完全同意仅在一个位置设置相应字段的想法,那么您仍然可以选择避免 CA2000,例如调用更智能的私有构造函数。 eg:例如:

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;
    }
}

Personally, I think the above is pretty nasty hack, particularly given that it involves increasing both code complexity and the chances of a runtime exception in the interests of avoiding a potential problem that wasn't very serious in the first place.就我个人而言,我认为以上内容是非常讨厌的 hack,特别是考虑到它涉及增加代码复杂性和运行时异常的机会,以避免一开始并不严重的潜在问题。 My recommendation would be to simply ignore potential CA2000 violations of this sort unless both of the following are true:我的建议是简单地忽略此类潜在的 CA2000 违规行为,除非以下两个都成立:

  1. There is a real chance of a non-crashing exception between the instantiation of the object and the end of the method in which it is assigned to a field.在 object 的实例化和将其分配给字段的方法结束之间确实有可能发生非崩溃异常。
  2. The consequences of failing to dispose the orphaned instance are fairly serious (eg: leaving a file locked).未能处理孤立实例的后果是相当严重的(例如:锁定文件)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM