2

我正在为自己的学习/成长编写一个 IoC 容器。通常我会写如下内容:

using(DisposableObject dispObj = new DisposableObject())
{
    UserRepository users = new UserRepository(dispObj);

    // Do stuff with user.
}

会转向:

using(IDisposableObject dispObj = Container.Resolve<IDisposableObject>())
{
    IUserRepository users = Container.Resolve<IUserRepository>();

    // Do stuff with user.
}

如何抽象 DisposableObject 以便它是using使用 IoC 时范围内使用的唯一实例?我试图弄清楚 Autofac 是如何做到的,但我并不完全确定。

编辑:当使用using范围实例化对象时,解析该类型的所有调用(在本例中IDisposableObject)都应返回范围变量,而不是新实例。同样重要的是,在using语句之后,另一个Resolve<IDisposableObject>被调用,它返回一个实例。

4

2 回答 2

2

以这种方式使用一次性对象时要记住的是,容器中的引用也会被释放,因此理想情况下,当您通过 Resolve<> 返回一个实例时,每次都需要返回一个新实例。

您需要做的是,在向容器注册类型时,允许它指定行为,共享(单例)或非共享,例如:

Container.RegisterType<IDisposableObject>(CreationPolicy.NonShared);

using (var disposable = Container.Resolve<IDisposableObject>()) {

}

上述方法适用于 NonShared 实例,因为每次都会创建一个新实例,因此我们可以安全地处理它。如果您尝试使用 CreationPolicy = Shared 进行上述操作,Singleton 将被丢弃,因此将来的访问可能会导致 ObjectDisposedException。

通过构建此行为,您可以通过传递 CreationPolicy = Shared 创建 Singleton 实例,例如:

Container.RegisterType<IUserRepository>(CreationPolicy.Shared);

using (var disposable = Container.Resolve<IDisposableObject>()) {
    var userRepository = Container.Resolve<IUserRepository>();
    // only one instance of user repository is created and persisted by the container.
}

希望有帮助吗?

如果您以前使用过 MEF,那么这个术语可能会很熟悉。

编辑:所以,我的理解是你想做这样的事情:

using (var repository = Container.Resolve<IUserRepository>())
{
  var other = Container.Resolve<IUserRepository>();
  // should resolve to the same instance.
}

您需要找到某种方法来监控容器中的一次性对象。也许引入一个额外的创建策略,SharedScope,例如:

Container.Register<IUserRepository, UserRepository>(CreationPolicy.SharedScope);

现在,当您使用容器解析类型时,您需要找出项目的 CreationPolicy。如果该项目是 SharedScope,并且尚未创建,则创建它的一个实例并返回。

如果您解析实例并且它已经创建,则返回现有实例。

当对该项目调用 Dispose 时,您需要某种方式回调到容器以删除实例。

编辑二

好吧,没有一种简单的方法可以解决这个问题。我能想到的唯一方法是你引入另一个接口:

public interface IMonitoredDisposable : IDisposable
{
  bool IsDisposed { get; set; }
}

释放对象时,请确保它设置 IsDisposed 属性。然后您可以从您的容器中监控该属性吗?

于 2010-06-30T18:07:12.990 回答
2

您可以返回一个类型的对象Owned<Foo>而不是Foo.

Owned<T>可能看起来像这样:

public class Owned<T> : IDisposable
{
   private readonly Container container;
   private readonly T value;

   public Owned(Container container, T value)
   {
      this.container = container;
      this.value = value;
   }

   public T Value { get { return value; } }

   public void Dispose()
   {
      this.container.ReleaseOwned(this);
   }

}

现在,客户端拉动Owned<Foo>可以通过处置对象来通知容器已完成对象,即使它Foo本身不是一次性的。这样,容器就知道何时清理对象及其依赖项(这也可能是一次性的,但对客户端不可见),并且您可以实现您所追求的行为。

Autofac 做了一些非常相似的事情。请参阅Nicholas Blumhardt 的博客文章The Relationship Zoo,他在其中介绍了这个概念。

于 2010-07-01T01:01:50.957 回答