简体   繁体   中英

Why does Code Analysis fire CA2000 on this method?

Visual Studio Code Analysis generates the warning "Dispose objects before losing scope" (CA2000) on the monitor variable in this method.

private void MonitorJob(IJob job, CancellationToken cancellationToken)
{
    var monitor = new JobMonitor(job, _backend);  // <- CA2000
    try
    {
        var task = monitor.Run(cancellationToken);
        _activeJobs[task] = monitor;
    }
    catch
    {
        monitor.Dispose();
        throw;
    }
}    

I understand what CA2000 does, and I'm usually able to work out why my code violates the rule and make the appropriate changes.

In this case, however, I'm stumped - is this really a false positive, or am I missing something?

Using Visual Studio 2015 Enterprise Edition, targeting .NET 4.5, using C# 6.

You could leak this disposable if an exception is thrown here:

private void MonitorJob(IJob job, CancellationToken cancellationToken)
{
    var monitor = new JobMonitor(job, _backend);

    // <- Exception

    try
    {
        var task = monitor.Run(cancellationToken);
        _activeJobs[task] = monitor;
    }
    catch
    {
        monitor.Dispose();
        throw;
    }
}

This could be caused by say a ThreadAbortException or any other exception that's injected into a thread by the runtime. I'd suggest declaring the variable outside of the try block but assign it within. Also, set it to null on successfully assigning it to _activeJobs .

private void MonitorJob(IJob job, CancellationToken cancellationToken)
{
    JobMonitor monitor;

    try
    {
        monitor = new JobMonitor(job, _backend);
        var task = monitor.Run(cancellationToken);
        _activeJobs[task] = monitor;
        monitor = null;
    }
    finally
    {
        if(monitor!=null)
        {
            monitor.Dispose();
        }
        throw;
    }
}

Even then though, it may not be enough to shut up the warning, at which point I'd suggest adding a suppression for it.

I assume that _activeJobs[task] = monitor; is a simple assignment and doesn't throw exception. If so separate storing monitor from creating monitor.

private void MonitorJob(IJob job, CancellationToken cancellationToken)
{
    Task task;
    var monitor = CreateJobMonitor(job, _backend, out task);
    _activeJobs[task] = monitor;
} 

private JobMonitor CreateJobMonitor(IJob job, CancellationToken cancellationToken, out Task task)
{
    var monitor = new JobMonitor(job, _backend);
    try
    {
        task = monitor.Run(cancellationToken);
        return monitor;
    }
    catch
    {
        monitor.Dispose();
        throw;
    }

This way, CreateJobMonitor means either returning a valid object or throwing exception. There is no chance to return disposed object reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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