Class 级变量与 CA2000 警告方法的区别

Difference between Class level variable and method for CA2000 Warning

我正在为使用 .net 的 SPA 应用程序开发 Web Api。当我在方法中使用实例化对象时,我收到 CA2000 警告。但是当我在 class 级别声明相同的对象时,CA2000 警告消失了。从下面看,示例 1 给出了 CA2000 警告,而示例 2 没有。为什么?

示例 1-

public class CodeGenAPIController : ApiResponseController
{
    NextGenCodeGen.CodeGenerator getEndPoint(TokenManager.TokenData tokenData, int BranchId)
    {
        NextGenCodeGen.CodeGenerator ret = null;
        lock (branchGenLock)
        {
            if (branchGenerators.ContainsKey(BranchId))
                ret = branchGenerators[BranchId];
        }
        if (ret == null)
        {
            string services = ConfigurationValuesAPIController.GetBranchProperties(tokenData.DatabaseIdentifier, BranchId).FirstOrDefault(x => x.Key == "AvailableCodeGenServices").Value;

            string[] endpoints = services.Split(new char[] { ' ', '.' }, StringSplitOptions.RemoveEmptyEntries);
            if (endpoints.Length == 0)
                throw new ArgumentOutOfRangeException("AvailableCodeGenServices",
                    string.Format("There appear to be no Code Generation Services configured for branch {0}", BranchId));

            string endpoint = endpoints[0];
            if (!endpoint.ToLower().EndsWith(".asmx"))
                endpoint = endpoint + ".asmx";

            //OBJECT INSTANTIATION INSIDE THE METHOD
            ret = new My_API.NextGenCodeGen.CodeGenerator() { Url = endpoint, UseDefaultCredentials = true};**
            lock(branchGenLock)
            {
                branchGenerators[BranchId] = ret;
            }
        }
        return ret;         
    }
 }

示例 2-

public class CodeGenAPIController : ApiResponseController
{
   //OBJECT INSTANTIATION OUTSIDE THE METHOD AT THE CLASS LEVEL
   NextGenCodeGen.ARGenTCodeGenerator retVal = new My_API.NextGenCodeGen.ARGenTCodeGenerator();

   NextGenCodeGen.CodeGenerator getEndPoint(TokenManager.TokenData tokenData, int BranchId)
    {
        retVal = null;
        lock (branchGenLock)
        {
            if (branchGenerators.ContainsKey(BranchId))
                retVal = branchGenerators[BranchId];
        }
        if (retVal == null)
        {
            string services = ConfigurationValuesAPIController.GetBranchProperties(tokenData.DatabaseIdentifier, BranchId).FirstOrDefault(x => x.Key == "AvailableCodeGenServices").Value;

            string[] endpoints = services.Split(new char[] { ' ', '.' }, StringSplitOptions.RemoveEmptyEntries);
            if (endpoints.Length == 0)
                throw new ArgumentOutOfRangeException("AvailableCodeGenServices",
                    string.Format("There appear to be no Code Generation Services configured for branch {0}", BranchId));

            string endpoint = endpoints[0];
            if (!endpoint.ToLower().EndsWith(".asmx"))
                endpoint = endpoint + ".asmx";
            retVal = new My_API.NextGenCodeGen.CodeGenerator();
            retVal.Url = endpoint;
            retVal.UseDefaultCredentials = true;

            lock (branchGenLock)
            {
                branchGenerators[BranchId] = retVal;
            }
        }
        return retVal;
    }
 }

通过在 class 级别声明变量,您将其范围限定为 class 实例。即使您在函数中 re-initialize 它,它的作用域仍然在函数外部。根据 CA2000 文档,这不会触发警告,因为 "all references to it are out of scope" 不正确。

官方文档:https://msdn.microsoft.com/en-us/library/ms182289.aspx

由于在第一个示例中发出了警告,这应该表明 My_API.NextGenCodeGen.CodeGenerator 实现了 IDisposable。如果为真,则考虑向此 class 添加一个 Dispose 处理程序并在那里执行任何 class-owned IDisposable 变量清理。垃圾收集器将处理其余部分。

如果您的 ApiResponseController 继承了 ApiController,那么您已经拥有车辆,只需驾驶即可:

public abstract class ApiController : IHttpController, IDisposable

在 class 情况下,应该 跳闸 CA2213 而不是 CA2000。 https://msdn.microsoft.com/en-us/library/ms182328.aspx

CA2213 似乎有一个限制,它无法确定如何处理实现 IDisposable 的基础 classes。在下面的示例中,FileIo 继承自 IoBase 并且不会引发警告。 FileIo2 仅实现 IDisposable 并且 确实 引发警告。

public class IoBase : IDisposable
{
  public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
    }
}
public class FileIo: IoBase
{
    private Stream io = new FileStream("c:\tmp\tmp.txt", FileMode.OpenOrCreate);
}

public class FileIo2 : IDisposable
{
    private Stream io = new FileStream("c:\tmp\tmp.txt", FileMode.OpenOrCreate);
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
    }
}