工厂应该跟踪创建的IDisposable对象吗?

时间:2014-12-18 06:16:29

标签: c# dispose idisposable factory-pattern

考虑以下简单的工厂示例:

public class MyFactory : IMyFactory
{
    public MyObject CreateObject()
    {
        return new MyObject();
    }
}

在此示例中,MyObject实现了IDisposable接口。通常我希望消费程序使用如下:

// Use using to properly dispose of MyObject
using (MyObject obj = myFactory.CreateObject())
{
    // ...
}

通常的做法是期望消费工厂的开发人员处理这样的处理吗?或者工厂应该保留它创建的对象列表,并确保它们定期清理,或者可能在工厂处置时清理?

5 个答案:

答案 0 :(得分:11)

实现IDisposable的类型为该类型的使用者提供了一种确定性地清理该类型使用的任何非托管资源的方法。例如,当处置FileStream时,底层OS文件句柄将被关闭。

直接使用非托管资源(例如文件句柄,数据库连接,本机套接字等)的任何正确实现的类型也将具有终结器,以在对象被垃圾回收时释放非托管资源。该类型的使用者可以使用IDisposable来确定性地释放非托管资源,或者只是等待垃圾收集器执行此操作。在大多数情况下,您希望走确定性路线。例如,您不希望在从其他进程访问文件之前等待垃圾收集器。您希望在使用该文件后立即关闭该文件。

因此垃圾收集器与终结器一起执行您尝试委托给工厂的任务,并且因为您的工厂不是垃圾收集器,您可能很难实际实现这种“跟踪和自动清理” ”

所以我对你的问题的主要答案是,不,工厂不应该跟踪创建的IDisposable个对象。

但是,如果您的工厂是某种控制所创建对象生命周期的容器,则可以使工厂自己IDisposable,然后处置所有创建的对象。这是依赖注入容器中的常见模式,用于响应请求周期,如Web应用程序。容器在请求开始时创建,并在响应完成时处理。工厂创建的类型的消费者不知道在请求结束时必须处理某些类型的事实。

答案 1 :(得分:1)

"取决于"

当工厂创建IDisposable个对象时,客户端处理它们通常是有意义的。

但是常见的工厂模式是使用其他一次性物品生成内置的物体,但不是本身一次性物品。为什么要这么做?由于IDisposable的病毒性质:

如果您的类型由其他5种内部类型组成,并且只有"最内部"是IDisposable您可以选​​择:

  • 你可以在所有5种类型上实现IDisposable模式,这样当你处理"最外面的"例如,一个正品一次性正确处理。 这显然需要相当多的瑕疵并影响你作品中每种类型的设计。
  • 或者,您可以从工厂将一个原装一次性注入您的对象组合物中,让工厂管理一次性用品的使用寿命。通过这种方式,工厂开始填补更多的终身管理角色。

你确实在现实世界中看到了这两种方法的例子,但我个人不喜欢仅仅因为病毒原因而实现IDisposable(即我的类型正在创建IDisposable所以必须IDisposable }本身 - 根据.NET Framework设计指南)。

WCF的ChannelFactory会保留其创建的所有频道的列表,并在Dispose出厂时将其关闭。类似地,许多IoC容器(它们本身就是超级工厂)通过StructureMap的GetNestedContainer()或Autofac的BeginLifetimeScope()

等内容支持终身管理角色。

答案 2 :(得分:0)

实施IDisposable时,您必须自己实施每个班级的清洁方法。换句话说,GC将无法正常导致内存泄漏。

我个人建议每个实现IDisposable的对象都应该知道如何清理自己。

如果您的工厂仅创建并返回实例而不保留每个实例的列表,则管理external resourcesunmanaged resources的每个类都应实现IDisposable

答案 3 :(得分:0)

绝对不是。即使在现实世界的例子中,没有真正的工厂跟踪其产品在其使用寿命后被破坏。

有趣的是,我没有就一个非常简单的问题进行一些技术讨论。为了理解我们理解术语的类比:

<强> FACTORY: 用于指向负责创建可以处理的类型实例的对象的术语。

LIFE TIME MANAGER: 用于指向负责创建实例的生命周期的对象的术语。它通常与多个相关实例一起使用,例如在依赖关系解析器的情况下,它可以在依赖对象超出范围时立即处理依赖关系对象。

因此,最好不要在一个类中不必要地占用这么多东西。 我很感激专家对此的看法。

答案 4 :(得分:0)

如果工厂不信任使用其创建的对象的代码将可靠地调用Dispose,则可能需要让工厂保留对此类对象的弱引用链接以及必要的信息。清理它们。这是一个丑陋的模式,但在某些情况下,如果确保废弃的物体得到清理是很重要的,那么它可能比任何可行的替代品更好。虽然有时使用析构函数或Finalize让生产的对象自行清理,但还有其他时候让工厂负责清理工作会更好。例如,如果工厂的产品订阅了工厂的逻辑事件,那么正常的事件订阅将使这些对象在工厂的生命周期内不会被最终确定。如果工厂为这些对象保留WeakReference列表,则每个通知都可以使所有活动对象调用其通知方法,并使所有死对象从列表中删除WeakReference