Как исправить предупреждение компилятора C # CA2000 IDisposable при использовании глобального кэша - PullRequest
6 голосов
/ 13 июля 2011

CA2000 является предупреждением относительно интерфейса IDisposable:

CA2000: Microsoft.Reliability: в методе 'ImportProcessor.GetContext (string)' вызовите System.IDisposable.Dispose для объекта 'c' передвсе ссылки на него выходят за рамки.

Мой метод используется для хранения кэша контекста, например так:

public class RegionContext : IDisposable { /* Implement Dispose() here */ } 

private Dictionary<string, RegionContext> contextCache = new ..... ();

public RegionContext GetContext(string regionCode)
{
    RegionContext rc = null;

    if (!this.contextCache.TryGetValue(regionCode.ToUpper(), out rc))
    {
        rc = new RegionContext(regionCode);
        this.contextCache.Add(regionCode.ToUpper(), rc);
    }

    return rc;
}

Где бы вы использовали оператор using(), которыйисправляет это предупреждение компилятора?

Мой внешний класс фактически выполняет итерацию и удаляет содержимое в contextCache в своей собственной реализации.Должен ли я подавить это или есть способ правильно избавиться от этого предупреждения?

Ответы [ 3 ]

12 голосов
/ 14 июля 2011

Это предупреждение CA2000 появляется всякий раз, когда у вас есть возвращаемое значение, которое IDisposable, и не обрабатывает случай, когда метод вызывает исключение.В этом случае вызывающая сторона не получит действительного экземпляра вашего объекта, поэтому it не сможет его утилизировать.Поэтому вы должны.

Я предполагаю, что вы не захотите избавиться от объекта, если успешно извлечете его из кэша.В этом случае вам нужно будет сделать что-то подобное, чтобы убедиться, что объект, который вы можете создать локально, будет расположен во всех случаях:

public RegionContext GetContext(string regionCode)
{
    RegionContext temp = null;
    RegionContext rc = null;

    try
    {
        if (!this.contextCache.TryGetValue(regionCode.ToUpper(), out rc))
        {
            temp = new RegionContext(regionCode);
            this.contextCache.Add(regionCode.ToUpper(), temp);

            rc = temp;
            temp = null;
        }

        return rc;
    }
    finally 
    {
        if ( temp != null ) 
        {
             temp.Dispose();
        }
    }
}
6 голосов
/ 14 июля 2011

На что CA2000 жалуется, так это то, что переменная может быть «осиротевшей» в нераспределенном состоянии, если при попытке добавить ее в кеш есть исключение.Чтобы полностью устранить проблему, вы можете добавить команду try / catch следующим образом (переменная newContext используется только для того, чтобы CA2000 могла обнаружить исправление):

public RegionContext GetContext(string regionCode)
{
    RegionContext rc = null;
    if (!this.contextCache.TryGetValue(regionCode.ToUpper(), out rc))
    {
        RegionContext newContext = new RegionContext(regionCode);
        try
        {
            this.contextCache.Add(regionCode.ToUpper(), newContext);
        }
        catch
        {
            newContext.Dispose();
            throw;
        }

        rc = newContext;
    }

    return rc;
}

Лично я нахожу такие вещибыть несколько нелепым излишним в большинстве случаев, но ммм ...

0 голосов
/ 25 апреля 2017

Решение Майкла, похоже, не работает при конвертации в VB.Net. Следующие две функции были протестированы в рамках VS 2017:

    Public Function OpenStream(ByVal filePathName As String) As System.IO.FileStream
        Dim fileStream As System.IO.FileStream = Nothing
        Dim tempFileStream As System.IO.FileStream = Nothing
        If Not String.IsNullOrWhiteSpace(filePathName) Then
            Try
                tempFileStream = New System.IO.FileStream(filePathName, System.IO.FileMode.Open, System.IO.FileAccess.Read)
                fileStream = tempFileStream
            Catch
                tempFileStream?.Dispose()
                Throw
            End Try
        End If
        Return fileStream
    End Function

    Public Function OpenReader(ByVal filePathName As String) As System.IO.BinaryReader
        If String.IsNullOrWhiteSpace(filePathName) Then Throw New ArgumentNullException(NameOf(filePathName))
        If Not System.IO.File.Exists(filePathName) Then Throw New System.IO.FileNotFoundException("Failed opening a binary reader -- file not found.", filePathName)
        Dim tempReader As System.IO.BinaryReader = Nothing
        Dim reader As System.IO.BinaryReader = Nothing
        Dim stream As IO.FileStream = Nothing
        Try
            stream = Methods.OpenStream(filePathName)
            tempReader = New System.IO.BinaryReader(stream)
            reader = tempReader
        Catch
            stream?.Dispose()
            tempReader?.Dispose()
            Throw
        End Try
        Return reader
    End Function
...