代码之家  ›  专栏  ›  技术社区  ›  Tarik

字段成员与方法变量?

  •  2
  • Tarik  · 技术社区  · 14 年前

    最近我一直在考虑类字段成员和方法变量之间的性能差异。我的确切意思是在下面的例子中:

    假设我们有一个 DataContext 对象 LIQ2SQL

    class DataLayer
    {
        ProductDataContext context = new ProductDataContext();
    
        public IQueryable<Product> GetData()
        {
           return context.Where(t=>t.ProductId == 2);
        }
    }
    

    在上面的示例中,上下文将存储在堆中,并且 GetData 方法变量将在方法执行后从堆栈中移除。

    因此,让我们检查下面的示例来进行区分:

    class DataLayer
    {
        public IQueryable<Product> GetData()
        {
           ProductDataContext context = new ProductDataContext();
           return context.Where(t=>t.ProductId == 2);
        }
    } 
    

    (* 1) 好吧,我们首先知道的是,如果我们定义 ProductDataContext 实例作为一个字段,我们可以在类中的任何地方访问它,这意味着我们不必一直创建相同的对象实例。

    但是假设我们谈论的是ASP.NET,一旦用户按下提交按钮,发布数据就会发送到服务器,事件就会执行,发布数据通过上述方法存储在数据库中,所以同一个用户可能会彼此发送不同的数据。如果在执行页面后我知道正确,那么终结器发挥作用,从内存(堆)中清除内容,这意味着我们也会从内存中丢失实例变量,在另一个日志之后, 数据上下文 应该为新页面周期再次创建。

    因此,向全班公开声明它的唯一好处似乎就是上面的第一个文本。

    或者还有别的什么?

    事先谢谢…

    (如果我说了不正确的话,请纠正我。)

    4 回复  |  直到 14 年前
        1
  •  6
  •   Community CDub    7 年前

    当涉及到每个方法或每个类实例创建一个对象之间的性能差异时,我不会对此担心太多。然而,您在这里似乎忽略了一些关于DataContext类和工作单元模式的重要原则。

    DataContext类作为单个工作单元运行。因此,您可以创建一个DataContext,创建对象,更新和删除对象,提交所有更改,然后释放DataContext。您可以为每个请求创建多个DataContext类,每个(业务)事务一个。但是在ASP.NET中,您不应该创建在Web请求之后仍然存在的DataContext。请求期间创建的所有数据上下文都应在该请求结束时或结束之前释放。这有两个原因。

    首先,DataContext具有从数据库中提取的所有对象的内部缓存。长时间使用数据上下文将使其缓存无限增长,并且当您拥有一个大数据库时,可能会导致内存问题。DataContext也会在可能的时候从缓存中返回一个对象,使您的对象很快过时。对另一个DataContext或直接对数据库进行的任何更新和删除操作都可能由于这种过时而不被注意。

    不缓存数据上下文的第二个原因是它们不是线程安全的。最好将数据上下文视为工作单元或(业务)事务。创建一组新对象,将它们添加到数据上下文,更改其他对象,删除一些对象,完成后,调用SubmitChanges。如果另一个请求在该操作期间调用同一实例上的SubmitChanges,那么您将失去事务的概念。当您允许代码这样做时,在最幸运的情况下,您的新对象将被持久化,您的事务将被拆分为两个单独的事务。最坏的情况是,您将数据上下文或其持久存在的对象保留在无效状态,这可能意味着其他请求失败或无效数据进入数据库。这不太可能是一个场景,我发现在开发人员为每个网站创建一个单一(静态)数据上下文的项目上会发生奇怪的事情。

    因此,考虑到这一点,让我们回到您的问题上来。虽然将DataContext定义为实例字段不是问题,但了解如何使用 DataLayer 班级。当你创建一个 数据层 每次请求或每次方法调用,您可能是安全的,但在这种情况下,您不应该存储 数据层 在静态字段中。当您想这样做时,应该为每个方法调用创建一个DataContext。

    重要的是要知道 数据层 类是。在代码中,您只向我们显示一个查询方法。没有CUD方法。每个方法都是一个事务,还是要调用多个方法并在 数据层 之后呢?当需要最后一个选项时,需要存储 DataContext 作为一个实例字段,在这种情况下,您应该实现 IDisposable 数据层 . 当每个方法都是它自己的事务时,可以为每个方法创建一个DataContext,并且应该在using语句中包装一个DataContext。但是请注意,当从方法返回具有延迟加载属性的对象时,处理DataContext可能会导致问题。释放DataContext后,无法再加载这些属性。 Here 更有趣的信息。

    如您所见,我甚至没有讨论您的两个选项中哪一个对性能更好,因为当解决方案给出不一致和不正确的结果时,性能并不重要。

    很抱歉我的回答太长了:-)

        2
  •  4
  •   casperOne    14 年前

    你从来都不想储存 DataContext class 在课堂上。如果您这样做,那么您将必须实现 IDisposable interface 在你的班上打电话给 Dispose 方法当你知道你已经完成了。

    最好在方法中创建一个新的DataContext并使用 using statement 完成后自动处理。

    尽管在DataContext上实现IDisposable没有任何作用,但这是 实施 详细信息,而公开IDisposable接口是 合同 你应该一直遵守。

    如果您将linq升级到实体并使用 ObjectContext class 你在哪里 必须 处理完实例后调用Dispose,否则资源将泄漏,直到下次垃圾收集。

        3
  •  1
  •   kemiller2002    14 年前

    所以这似乎是 向全体公开宣布 类是唯一的第一个文本 上面。

    是的,声明一个类级变量是为了允许整个类访问同一个变量。它不应该被用来试图故意阻止垃圾收集的发生。属性、方法等的访问修饰符用于确定类的外部或内部对象可以使用该代码访问/修改/猴子。

    在ASP.NET中,一旦请求发送到浏览器,无论变量是否为公共变量,为该页请求创建的对象将来都将在某个时间点进行CGED。如果希望信息保持在请求之间,则需要创建对象的单例实例,或者将对象序列化为会话或应用程序状态。

        4
  •  1
  •   sinm    14 年前

    请参阅以下示例-“Linq to SQL DataContext生存期管理”: http://www.west-wind.com/weblog/posts/246222.aspx 这种方法使生活更简单。