C# 定制IoC-如何实现具有范围的DI?
我正在为自己的学习/成长编写一个IoC容器。通常我会写以下内容:C# 定制IoC-如何实现具有范围的DI?,c#,dependency-injection,inversion-of-control,autofac,C#,Dependency Injection,Inversion Of Control,Autofac,我正在为自己的学习/成长编写一个IoC容器。通常我会写以下内容: using(DisposableObject dispObj = new DisposableObject()) { UserRepository users = new UserRepository(dispObj); // Do stuff with user. } 我们将转向: using(IDisposableObject dispObj = Container.Resolve<IDisposab
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.
}
使用(IDisposableObject dispObj=Container.Resolve())
{
IUserRepository users=Container.Resolve();
//和用户一起做事。
}
在使用IoC时,如何提取DisposableObject,使其成为使用范围的中使用的唯一实例?我试图弄清楚Autofac是如何做到的,但我不完全确定
EDIT:当使用作用域实例化对象时,所有解析该类型的调用(在本例中为IDisposableObject
)都应返回作用域变量,而不是新实例。同样重要的是,在调用using
语句和另一个Resolve
之后,它返回一个新实例。以这种方式使用一次性对象时,要记住的是容器中的引用也会被释放,因此,理想情况下,当您通过Resolve返回实例时,每次都需要返回一个新实例
您需要做的是,在向您的容器注册类型时,允许它指定共享(单例)或非共享的行为,例如:
Container.RegisterType<IDisposableObject>(CreationPolicy.NonShared);
using (var disposable = Container.Resolve<IDisposableObject>()) {
}
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.
}
释放对象时,请确保它设置了IsDisposed属性。然后,您可以从容器中监视该属性吗?您可以返回类型为Owned
的对象,而不是Foo
拥有的
可能如下所示:
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);
}
}
拥有的公共类:IDisposable
{
专用只读容器;
私有只读T值;
公有(集装箱,T值)
{
this.container=容器;
这个值=值;
}
公共T值{get{return Value;}}
公共空间处置()
{
this.container.ReleaseOwned(this);
}
}
现在,客户机可以通过处理对象来通知容器已处理该对象,即使Foo
本身不是一次性的。通过这种方式,容器知道何时清理对象及其依赖项(也可能是一次性的,但对客户端不可见),并且您可以实现所追求的行为
Autofac也做了类似的事情。请看,尼古拉斯·布卢姆哈特(Nicholas Blumhardt)在博客中介绍了这一概念。这正是我想要的答案。我知道我需要通过某种“范围”。我只是想知道如果单件已被处理,如何从我的字典中删除它?我想到的一种方法是使用(var localContainer=IoC.Create())
为每个“scope”创建一个新的容器,然后调用localContainer.Resolve()
在本地进行解析……好吧,您不会处理单例,否则您将无法再次返回它们。如果您的容器有一个单例的内部哈希表,请将它们存储在可以轻松再次获取它们的位置。如果要解析的类型没有声明为Singleton,则只需通过Resolve返回它,而不存储它。使用带有一次性模式问题的容器并不是一个好办法,因为您每次都必须设置和创建容器……因此,如果您不处理单例,它们如何特定于使用
范围的?哈希表中的键始终会命中同一个单例(已释放或未释放),因为它没有被删除。我认为您忽略了一个问题,即如果我在using语句中调用Container.Resolve(),它应该引用从using
作用域创建的Container.Resolve()。Singleton被设计为单个实例。如果您处理了它们,它们就不能再使用了。这是因为你不会将它们与using块一起使用,而我仍然想知道的正是“对处置的监控”。我怎样才能继续监视某个东西,直到它被处理掉……昨晚我在看到你的帖子之前发现了同样的链接。唯一的问题是不是Resolve()然后返回Owned而不是t?那么,我的代码是否总是必须依赖于使用
语句的中的Owned,然后使用Owned.Value来获取实际的t?调用代码知道它是否需要所有权,因此它可以根据需要调用Resolve()
或Resolve
。或者,如果您不喜欢根据请求的类型更改语义,您可以使用单独的Resolve
和ResolveOwned
方法。好吧,如果我真的需要一些无法通知它已被处置的方法,那么这很有意义。
Container.Register<IUserRepository, UserRepository>(CreationPolicy.SharedScope);
public interface IMonitoredDisposable : IDisposable
{
bool IsDisposed { get; set; }
}
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);
}
}