字段成员与方法变量?

时间:2010-05-11 17:46:37

标签: c# asp.net class

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

假设我们有 Linq2SQL的DataContext对象

class DataLayer
{
    ProductDataContext context = new ProductDataContext();

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

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

因此,让我们检查以下示例以区分:

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

(* 1)所以我们知道的第一件事就是如果我们将ProductDataContext实例定义为一个字段,我们就可以在课堂的任何地方找到它,这意味着我们不需要始终创建相同的对象实例。

但是我们说我们正在讨论Asp.NET,一旦用户按下提交按钮,就会将数据发送到服务器并执行事件,并通过上述方法将发布的数据存储在数据库中,这样就很可能同一个用户可以一个接一个地发送不同的数据。如果我在页面执行后正确地知道,终结器就会从内存(从堆中)开始发挥作用,这意味着我们也会从内存中丢失实例变量。邮件,DataContext应该再次为新的页面循环创建。

因此,向全班公开宣布它的唯一好处就是上面的第一个文字。

或者还有别的吗?

提前致谢...

(如果我说错了,请修理我..)

4 个答案:

答案 0 :(得分:6)

当谈到每个方法或每个类实例创建一个对象之间的性能差异时,我不会太担心它。但是,您似乎在这里想到的是一般围绕DataContext类和工作单元模式的一些重要原则。

DataContext类作为单个工作单元运行。因此,您创建DataContext,创建对象,更新和删除对象,提交所有更改,然后在此之后释放DataContext。您可以为每个请求创建多个DataContext类,每个(业务)事务一个。但是在ASP.NET中,您永远不应该创建一个能够在Web请求中幸存的DataContext。请求期间或之前应处理请求期间创建的所有DataContexts。这有两个原因。

首先,DataContext具有从数据库中提取的所有对象的内部缓存。长时间使用DataContext将使其缓存无限增长,并且当您拥有一个大型数据库时可能会导致内存问题。 DataContext还支持在缓存中从缓存中返回对象,使您的对象快速失效。由于这种陈旧性,任何对另一个DataContext或直接对数据库进行的更新和删除操作都不会被注意到。

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

所以考虑到这一点,让我们回到你的问题。虽然将DataContext定义为实例字段不是问题,但了解如何使用DataLayer类非常重要。当您为每个请求或每个方法调用创建一个DataLayer时,您可能会安全,但在这种情况下,您不应将DataLayer存储在静态字段中。如果你想这样做,你应该为每个方法调用创建一个DataContext。

了解DataLayer类的设计非常重要。在您的代码中,您只向我们展示了一种查询方法。没有CUD方法。每个方法都是单个事务,还是要调用多个方法并在DataLayer之后调用SaveChanges?如果您需要最后一个选项,则需要将DataContext存储为实例字段,在这种情况下,您应该在IDisposable上实现DataLayer。当每个方法都是自己的事务时,您可以为每个方法创建一个DataContext,并且应该将一个DataContext包装在using语句中。但请注意,从方法返回具有延迟加载属性的对象时,处理DataContext可能会导致问题。处理DataContext时,无法再加载这些属性。 Here是关于此的更有趣的信息。

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

对不起,我很抱歉: - )

答案 1 :(得分:4)

您不希望在班级上存储DataContext class。如果您这样做,则必须在课程中实施IDisposable interface,并在知道完成后调用Dispose方法。

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

即使DataContext上的IDisposable的实现没有做任何事情,这是实现细节,而暴露IDisposable接口是契约,你应该始终遵守。< / p>

如果你升级到LINQ-to-Entities并使用你必须必须调用Dispose的ObjectContext class,那么,当你完成它时,它会特别方便,否则,资源将会泄漏直到下一次垃圾收集。

答案 2 :(得分:1)

  

所以这似乎是唯一的好处   向所有人公开宣布   class是唯一的第一个文本   上方。

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

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

答案 3 :(得分:1)

请参阅此示例 - “Linq to SQL DataContext Lifetime Management”:http://www.west-wind.com/weblog/posts/246222.aspx此方法使生活更简单。