简体   繁体   中英

Why does this method cause Code Analysis error CA2000: Call Dispose()

I'm building my project with the "Microsoft Minimal Rules" code analysis set and it gives me CA2000 on this method:

private Timer InitializeTimer(double intervalInSeconds)
{
    Timer timer = null;

    try
    {
        timer = new Timer { Interval = intervalInSeconds * 1000, Enabled = true };
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }
    catch
    {
         if (timer != null)
         {
             timer.Dispose();
         }
    }
    return timer;
}

This method just creates a new System.Timers.Timer from an interval in seconds. I have three such timers running (one for every second, one every minute and one every half hour). Maybe it's better to have one timer and check in the elapsed event handler whether a minute or a half hour has passed, but I don't know, this is easier at this time, it's inherited code and I don't want to break everything yet.

This method gives me the infamous

Warning 21  CA2000 : Microsoft.Reliability : In method 'TimerManager.InitializeTimer(double)', call System.IDisposable.Dispose on object '<>g__initLocal0' before all references to it are out of scope.

Now I AM calling Dispose in the catch and thought this would be enough? I'm also disposing all timers in the class' own IDisposable implementation.

What am I missing here?

You only call Dispose in case of an exception (which you should never handle with a catch-all block BTW, but that is another story). In case of a no exceptions, you don't dispose the Timer object.

Either add a finally block and move the Dispose there, or use a using block.

The warning tells you that you are creating a disposable object and not disposing it in all cases. If you are properly disposing it in some other method, then you can safely suppress this warning (you can do that using the SuppressMessageAttribute ).

Okay, I edited it like this:

private Timer InitializeTimer(double intervalInSeconds)
    {
        Timer tempTimer = null;
        Timer timer;
        try
        {
            tempTimer = new Timer();
            tempTimer.Interval = intervalInSeconds * 1000;
            tempTimer.Enabled = true;
            tempTimer.Elapsed += timer_Elapsed;
            tempTimer.Start();
            timer = tempTimer;
            tempTimer = null;
        }
        finally
        {
            if (tempTimer != null)
            {
                tempTimer.Dispose();
            }
        }
        return timer;
    }

This is per the CA2000 docs and it doesn't give a warning. I had overlooked the fact that the object initializer syntax creates a temporary object which may not be disposed.

Thanks, guys!

I think it is much better to use "using" instead of "try/finally" reference

private Timer InitializeTimer(double intervalInSeconds)
{
    Timer timer;
    using (var tempTimer = new Timer())
    {
        tempTimer.Interval = intervalInSeconds * 1000;
        tempTimer.Enabled = true;
        tempTimer.Elapsed += timer_Elapsed;
        tempTimer.Start();
        timer = tempTimer;
    }
    return timer;
}

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