['using'关键字vs实体框架的类字段

问题描述 投票:1回答:3

我知道using关键字在作用域结束后基本上会调用Dispose(),但是,使using子句中的变量成为类字段是不好的做法还是不可接受?示例:

public class ValuesController : ApiController
{
        DatabaseEntities db;

        public ValuesController()
        {
            db = new DatabaseEntities();
        }

        public IHttpActionResult GetList()
        {
            return Ok(db.Values.ToList());
        }
}

vs:

public class ValuesController : ApiController
{     
        public IHttpActionResult GetList()
        {
            using (DatabaseEntities db = new DatabaseEntities())
            {
                 return Ok(db.Values.ToList());
            }
        }
}

在第一个示例中,在API调用完成后[DatabaseEntities是否会正确处理?第一个例子是不好的做法吗?

c# entity-framework using-statement
3个回答
2
投票

将其封装在控制器中是安全的,但只有将其放置在控制器的Dispose(bool)中才可以。例如:

public class ValuesController : ApiController
{
    DatabaseEntities db;

    public ValuesController()
    {
        db = new DatabaseEntities();
    }

    public IHttpActionResult GetList()
    {
        return Ok(db.Values.ToList());
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }
}

但是使用DI比在控制器上覆盖Dispose(bool)更容易,因此这不是最佳实践。


2
投票

第一个例子是两个方面的错误做法

  1. 您应该使用DI库将依赖项注入控制器中

  2. 如果您的DatabaseEntities类使用非托管资源(例如,某些基于Win32构建的COM对象,等等),那么它将无法被GC正确处置;类本身可能会在超出范围时调用finaliser方法,但总的来说,依靠这些存在不是一个好主意。在某些情况下(例如,如果基础COM服务器的对象池有限,或者终结器崩溃等),这可能导致内存泄漏和服务丢失。

    [here的讨论很热烈>

    而且,即使它是完全托管的类,也要等到您的方案中的下一个GC周期,它才会被处理,最终结果是性能问题。

  3. 因此您的代码应如下所示(请注意,这里我使用的接口在抽象依赖的实际实现方面也被认为是一种好习惯)。

public class ValuesController : ApiController
{
        readonly IDatabaseEntities _db;

        //here db is being provided to the ctor by your
        //DI Library e.g. StructureMap, SimpleInjector, .Net Core Injection, etc.
        public ValuesController(IDatabaseEntities db)
        {
            _db = db; //null check left out for brevity
        }

        public IHttpActionResult GetList()
        {
            return Ok(_db.Values.ToList());
        }
}

这样做的好处是您的DI容器现在负责处理您的DatabaseEntities实例,而不是您。而且,它也使ValuesController更易于单独测试。

我有2条关于一次性用品的规则,这些规则从未让我失败:

  1. 切勿拆分创作和处置。创建,使用,处置。全部都在同一段代码中,最好使用using块。
  • 在某些情况下,您可能无法遵循规则1。主要是因为您的类包含Disposeable,因此需要保持打开状态。在这种情况下,您实现IDisposeable的唯一目的是中继dispose调用。实际上,这就是所有类中95%都实现IDisposeable的原因-因为它们可能必须执行这种中继。
  • 如果情况2谁使用您的班级,遵循规则1。

    使第2种情况除外的可处置对象的类字段实际上只会冒诸如“在已处置时尝试使用它”和“在没人要对其进行处理时尝试使用它的东西”之类的风险。这只会引起问题。


    0
    投票

    我有2条关于一次性用品的规则,这些规则从未让我失败:

    1. 切勿拆分创作和处置。创建,使用,处置。全部都在同一段代码中,最好使用using块。
    © www.soinside.com 2019 - 2024. All rights reserved.