C# Unity 2.0和处理IDisposable类型(尤其是PerThreadLifetimeManager)
我知道类似的问题被问了好几次(例如:,和),但对于Unity的早期版本,答案取决于使用的C# Unity 2.0和处理IDisposable类型(尤其是PerThreadLifetimeManager),c#,.net,inversion-of-control,unity-container,idisposable,C#,.net,Inversion Of Control,Unity Container,Idisposable,我知道类似的问题被问了好几次(例如:,和),但对于Unity的早期版本,答案取决于使用的LifetimeManager类 文件说: Unity使用继承的特定类型 来自LifetimeManager基类 (统称为终身 管理者)来控制it存储的方式 对对象实例的引用以及如何 容器处理这些 实例 好的,听起来不错,所以我决定检查内置生命周期管理器的实现。我的结论是: TransientLifetime管理器-无需处理。容器只解析实例,不跟踪它。调用代码负责处理实例 ContainerControll
LifetimeManager
类
文件说:
Unity使用继承的特定类型
来自LifetimeManager基类
(统称为终身
管理者)来控制it存储的方式
对对象实例的引用以及如何
容器处理这些
实例
好的,听起来不错,所以我决定检查内置生命周期管理器的实现。我的结论是:
-无需处理。容器只解析实例,不跟踪它。调用代码负责处理实例TransientLifetime管理器
-在释放生命周期管理器时(=释放容器时)处理实例。提供在层次结构中所有容器之间共享的单例实例ContainerControlled LifetimeManager
-从HierarchyCallifeTimeManager
派生行为。它在层次结构(子容器)中为每个容器提供“singleton”实例ContainerControlled LifetimeManager
-无需处理。正确的行为,因为容器不是实例的所有者外部控制的LifetimeManager
-不处理处置。它通常与PerResolveLifetimeManager
相同,但它允许在解析整个对象图时重用实例进行依赖注入TransientLifetimeManager
-不处理MSDN中描述的处置谁负责处置?PerThreadLifetimeManager
PerThreadLifetimeManager
的实现是:
public class PerThreadLifetimeManager : LifetimeManager
{
private readonly Guid key = Guid.NewGuid();
[ThreadStatic]
private static Dictionary<Guid, object> values;
private static void EnsureValues()
{
if (values == null)
{
values = new Dictionary<Guid, object>();
}
}
public override object GetValue()
{
object result;
EnsureValues();
values.TryGetValue(this.key, out result);
return result;
}
public override void RemoveValue()
{ }
public override void SetValue(object newValue)
{
EnsureValues();
values[this.key] = newValue;
}
}
公共类PerThreadLifetimeManager:LifetimeManager
{
私有只读Guid键=Guid.NewGuid();
[线程静态]
私有静态字典值;
私有静态资产重新估价()
{
如果(值==null)
{
值=新字典();
}
}
公共重写对象GetValue()
{
客观结果;
确保重新估价();
values.TryGetValue(this.key,out结果);
返回结果;
}
public override void RemoveValue()
{ }
公共覆盖无效设置值(对象新值)
{
确保重新估价();
values[this.key]=newValue;
}
}
因此,disposing container不会处置使用此生存期管理器创建的一次性实例。线程完成也不会处理这些实例。那么谁负责发布实例呢
我试图在代码中手动处理已解决的实例,但发现了另一个问题。我不能拆卸仪器。lifetime manager的RemoveValue为空-一旦创建实例,就无法将其从线程静态字典中删除(我还怀疑TearDown
方法没有任何作用)。因此,如果在处理实例后调用Resolve
,您将得到已处理的实例。我认为,当使用这个生命周期管理器处理线程池中的线程时,这可能是一个相当大的问题
如何正确使用此终身管理器
此外,此实现通常在自定义生存期管理器中重用,如PerCallContext、PerHttpRequest、PerAspNetSession、PerWcfCall等。只有线程静态字典被替换为其他构造
我是否正确理解处理一次性对象取决于lifetime manager?因此,应用程序代码取决于使用的生命周期管理器
我了解到,在其他IoC容器中,处理临时一次性对象的操作是由子容器处理的,但我没有找到Unity的示例-它可能可以由本地范围的子容器和HIEArchieCallifetimeManager处理,但我不确定如何处理。查看Unity 2.0源代码,闻起来好像LifetimeManager用于以不同的方式将对象保留在作用域中,这样垃圾收集器就不会丢弃它们。例如,对于PerThreadLifetimeManager,它将使用ThreadStatic在具有特定线程生命周期的每个对象上保存引用。但是,在容器被释放之前,它不会调用Dispose 有一个LifetimeContainer对象,用于保存创建的所有实例,然后在释放UnityContainer时释放(UnityContainer反过来按相反的时间顺序处理其中的所有IDisPobles)
编辑:仔细检查后,LifetimeContainer只包含LifeTimeManager(因此命名为“Lifetime”容器)。因此,当它被处理时,它只处理生命周期管理器。(我们面临着已经讨论过的问题)。使用HttpContext.Current.ApplicationInstance.EndRequest事件挂接到请求的末尾,然后处理存储在此生存期管理器中的对象,这是一个可行的解决方案吗?像这样:
public HttpContextLifetimeManager()
{
HttpContext.Current.ApplicationInstance.EndRequest += (sender, e) => {
Dispose();
};
}
public override void RemoveValue()
{
var value = GetValue();
IDisposable disposableValue = value as IDisposable;
if (disposableValue != null) {
disposableValue.Dispose();
}
HttpContext.Current.Items.Remove(ItemName);
}
public void Dispose()
{
RemoveValue();
}
您不必像其他解决方案那样使用子容器,用于处理对象的代码仍然像它应该使用的那样在生命周期管理器中。只有少数情况下Unity会处理实例。这确实是不受支持的。我的解决方案是一个自定义扩展来实现这一点-我最近在将Unity插入应用程序时遇到了这个问题。在我看来,我在Stack Overflow和其他网站上找到的解决方案似乎并没有以令人满意的方式解决这个问题 当不使用Unity时,IDisposable实例有一个很好理解的使用模式:
中,以“免费”获得处置
Dis中进行清理
public class SomeTypeFactory
{
// ... take IUnityContainer as a dependency and save it
IDependencyDisposer< SomeType > Create()
{
return this.unity.ResolveForDisposal< SomeType >();
}
}
public class BusinessClass
{
// ... take SomeTypeFactory as a dependency and save it
public void AfunctionThatCreatesSomeTypeDynamically()
{
using ( var wrapper = this.someTypeFactory.Create() )
{
SomeType subject = wrapper.Subject;
// ... do stuff
}
}
}