开发者

Making Custom IoC - How to Implement DI That Has Scope?

I'm writing an IoC container for my own learning/growth. Normally I would write something like the following:

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

    // Do stuff with user.
}

Would turn to:

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

    // Do stuff with us开发者_如何学JAVAer.
}

How can I abstract the DisposableObject so that it is the only instanced used in the using scope when using an IoC? I'm trying to figure out how Autofac does it but I'm not totally sure.

EDIT: When an object is instantiated with the using scope, all calls to resolve that type (in this case IDisposableObject) should return the scoped variable, and not a new instance. It's also important that after the using statement, and another Resolve<IDisposableObject> is called, it returns a new instance.


The thing to remember when using a disposable object in this fashion, is that the reference in the container would also be disposed, so ideally when you return an instance through Resolve<> it needs to return a new instance each time.

What you would need to do, is when registering types with your container, allow it to specify a behaviour, either Shared (Singleton), or NonShared, e.g.:

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

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

}

The above would work for NonShared instances, as a new instance is created each time, so we can safely dispose of it. If you tried the above with a CreationPolicy = Shared, the Singleton would be disposed of, so future access will likely result in an ObjectDisposedException.

By building this behaviour in, you can create Singleton instances by passing a CreationPolicy = Shared, e.g.:

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.
}

Hope that helps?

This terminology might be familiar if you have previously used MEF.

EDIT: So, my understanding is that you want to do something like:

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

You need to find some way of monitoring a disposable object in the container. Perhaps introduce an additional creation policy, SharedScope, e.g:

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

Now, when you resolve the type using the container, you'd need to figure out the CreationPolicy of the item. If the item is SharedScope, and it hasn't been created, create an instance of it and return.

If you resolve the instance and it has already been created, return the existing instance.

When Dispose is called on that item, you need some way to callback to the container to remove the instance.

EDIT TWO:

Well, there isn't an easy way of figuring that out. The only way I can think is that you introduce another interface:

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

When an object is disposed, make sure it sets the IsDisposed property. Could you then monitor that property from your container?


You could return an object of type Owned<Foo> instead of Foo.

Owned<T> might look like this:

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);
   }

}

Now the client pulling Owned<Foo> can notify the container that is done with the object by disposing it, even if Foo itself is not disposable. This way, the container knows when to clean up the object and its dependencies (which might also be disposable, but invisible to the client), and you can implement the behavior you're after.

Autofac does something very similar. See The Relationship Zoo, a blog post by Nicholas Blumhardt where he introduces this concept.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜