在 Unity 容器上调用 dispose 的最佳方式是什么?
What's the best way to call dispose on Unity Containers?
我下面有一个已完成(但已损坏)的 C# 应用程序,它会生成堆栈溢出异常。如果你查看源代码,你就会明白为什么会出现堆栈溢出异常,所以我并不是真的在诊断为什么会发生这种情况,我想知道最好的处理方法是什么。
1) 所有对 unity 的引用都封装在一个 Class 命名的注册表中,因此我可以毫无困难地升级。我不希望 unitycontainer 在可能的情况下乱扔其他 classes。理论上,我应该可以升级到 5 if/when 它出来了,甚至可以换成 ninject 或其他 DI 框架,如果我要有一个急剧变化的配置。
2) 我希望注册表由统一容器控制,以便它可以在容器控制的构造函数中使用 classes。 (例如 FirstSingleInstance)
3) IRegistry 和 Registry 都继承自 IDisposable,因为我认为处置统一容器是一种很好的做法。
4) Registry 在它自己的构造函数中构造 Unity 容器,因此我假设在调用 registry.dispose 时我也应该处理 unity 容器。
5) Registry 控制的所有其他 classes 应该是单个实例 classes,因此我使用 ContainerControlledLifetimeManager 注册它们。我希望这些实例将在容器被处置时被处置。
处理这种情况的最佳做法是什么?
a) 不要在 Registry 上调用 dispose -- 让它在进程线程的生命周期内存在?
b) 不要试图让 Registry(以及 UnityContainer)由 unity 容器控制。这样调用 Registry 上的 dispose 不会导致 Whosebug 异常。我将如何统一构建 FirstSingleInstance class 是我必须回顾的事情。
d) 其他?
这是我编写的包含所有相关部分的应用程序
using System;
using Microsoft.Practices.Unity;
namespace DIProblem.Console
{
class Program
{
static void Main(string[] args)
{
IRegistry registry = CreateRegistry();
IFirstSingleInstance theInstance = registry.Resolve<IFirstSingleInstance>();
theInstance.DoThis();
registry.Dispose(); // stack overflow here because of infinite dispose loop
}
static IRegistry CreateRegistry() => new Registry();
}
public class FirstSingleInstance : IFirstSingleInstance
{
private IRegistry _registry;
public FirstSingleInstance(IRegistry reg)
{
_registry = reg;
}
public void DoThis()
{
System.Console.WriteLine("This Was Done.");
_registry.Resolve<ISecondSingleInstance>().DoThisToo();
}
}
public class SecondSingleInstance : ISecondSingleInstance
{
private IRegistry _registry;
public SecondSingleInstance(IRegistry reg)
{
_registry = reg;
}
public void DoThisToo()
{
System.Console.WriteLine("This Was Done too.");
}
}
public interface ISecondSingleInstance
{
void DoThisToo();
}
public interface IFirstSingleInstance
{
void DoThis();
}
public class Registry : IRegistry, IDisposable
{
public Registry()
{
_container = new UnityContainer();
RegisterInstance<IFirstSingleInstance, FirstSingleInstance>();
RegisterInstance<ISecondSingleInstance, SecondSingleInstance>();
_container.RegisterInstance<IRegistry>(this);
}
private UnityContainer _container;
public void RegisterInstance<T1, T2>() where T2 : class, T1 => _container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
public T Resolve<T>() => _container.Resolve<T>();
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
_container?.Dispose();
_container = null;
}
}
public interface IRegistry : IDisposable
{
T Resolve<T>();
void RegisterInstance<T1, T2>() where T2 : class, T1;
}
}
感谢您以合理的方式提供帮助。
以下代码避免使用 Service Locator anti-pattern,而是仅依赖 构造函数注入 作为应用控制反转的模式。结果是一个更简单、更可维护和更可测试的应用程序,不会导致任何 Whosebug 异常。
class Program
{
static void Main(string[] args)
{
using (var container = Registry.BuildContainer())
{
var theInstance = registry.Resolve<IFirstSingleInstance>();
theInstance.DoThis();
}
}
}
public static class Registry
{
public static UnityContainer BuildContainer()
{
var container = new UnityContainer();
container.RegisterType<IFirstSingleInstance, FirstSingleInstance>(Singleton);
container.RegisterType<ISecondSingleInstance, SecondSingleInstance>(Singleton);
return container;
}
private static ContainerControlledLifetimeManager Singleton =>
new ContainerControlledLifetimeManager();
}
public interface ISecondSingleInstance
{
void DoThisToo();
}
public interface IFirstSingleInstance
{
void DoThis();
}
public class FirstSingleInstance : IFirstSingleInstance
{
private ISecondSingleInstance _second;
public FirstSingleInstance(ISecondSingleInstance second)
{
_second = second;
}
public void DoThis()
{
System.Console.WriteLine("This Was Done.");
_second.DoThisToo();
}
}
public class SecondSingleInstance : ISecondSingleInstance
{
public SecondSingleInstance(/* other dependencies here */)
{
}
public void DoThisToo()
{
System.Console.WriteLine("This Was Done too.");
}
}
我下面有一个已完成(但已损坏)的 C# 应用程序,它会生成堆栈溢出异常。如果你查看源代码,你就会明白为什么会出现堆栈溢出异常,所以我并不是真的在诊断为什么会发生这种情况,我想知道最好的处理方法是什么。
1) 所有对 unity 的引用都封装在一个 Class 命名的注册表中,因此我可以毫无困难地升级。我不希望 unitycontainer 在可能的情况下乱扔其他 classes。理论上,我应该可以升级到 5 if/when 它出来了,甚至可以换成 ninject 或其他 DI 框架,如果我要有一个急剧变化的配置。
2) 我希望注册表由统一容器控制,以便它可以在容器控制的构造函数中使用 classes。 (例如 FirstSingleInstance)
3) IRegistry 和 Registry 都继承自 IDisposable,因为我认为处置统一容器是一种很好的做法。
4) Registry 在它自己的构造函数中构造 Unity 容器,因此我假设在调用 registry.dispose 时我也应该处理 unity 容器。
5) Registry 控制的所有其他 classes 应该是单个实例 classes,因此我使用 ContainerControlledLifetimeManager 注册它们。我希望这些实例将在容器被处置时被处置。
处理这种情况的最佳做法是什么?
a) 不要在 Registry 上调用 dispose -- 让它在进程线程的生命周期内存在?
b) 不要试图让 Registry(以及 UnityContainer)由 unity 容器控制。这样调用 Registry 上的 dispose 不会导致 Whosebug 异常。我将如何统一构建 FirstSingleInstance class 是我必须回顾的事情。
d) 其他?
这是我编写的包含所有相关部分的应用程序
using System;
using Microsoft.Practices.Unity;
namespace DIProblem.Console
{
class Program
{
static void Main(string[] args)
{
IRegistry registry = CreateRegistry();
IFirstSingleInstance theInstance = registry.Resolve<IFirstSingleInstance>();
theInstance.DoThis();
registry.Dispose(); // stack overflow here because of infinite dispose loop
}
static IRegistry CreateRegistry() => new Registry();
}
public class FirstSingleInstance : IFirstSingleInstance
{
private IRegistry _registry;
public FirstSingleInstance(IRegistry reg)
{
_registry = reg;
}
public void DoThis()
{
System.Console.WriteLine("This Was Done.");
_registry.Resolve<ISecondSingleInstance>().DoThisToo();
}
}
public class SecondSingleInstance : ISecondSingleInstance
{
private IRegistry _registry;
public SecondSingleInstance(IRegistry reg)
{
_registry = reg;
}
public void DoThisToo()
{
System.Console.WriteLine("This Was Done too.");
}
}
public interface ISecondSingleInstance
{
void DoThisToo();
}
public interface IFirstSingleInstance
{
void DoThis();
}
public class Registry : IRegistry, IDisposable
{
public Registry()
{
_container = new UnityContainer();
RegisterInstance<IFirstSingleInstance, FirstSingleInstance>();
RegisterInstance<ISecondSingleInstance, SecondSingleInstance>();
_container.RegisterInstance<IRegistry>(this);
}
private UnityContainer _container;
public void RegisterInstance<T1, T2>() where T2 : class, T1 => _container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
public T Resolve<T>() => _container.Resolve<T>();
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
_container?.Dispose();
_container = null;
}
}
public interface IRegistry : IDisposable
{
T Resolve<T>();
void RegisterInstance<T1, T2>() where T2 : class, T1;
}
}
感谢您以合理的方式提供帮助。
以下代码避免使用 Service Locator anti-pattern,而是仅依赖 构造函数注入 作为应用控制反转的模式。结果是一个更简单、更可维护和更可测试的应用程序,不会导致任何 Whosebug 异常。
class Program
{
static void Main(string[] args)
{
using (var container = Registry.BuildContainer())
{
var theInstance = registry.Resolve<IFirstSingleInstance>();
theInstance.DoThis();
}
}
}
public static class Registry
{
public static UnityContainer BuildContainer()
{
var container = new UnityContainer();
container.RegisterType<IFirstSingleInstance, FirstSingleInstance>(Singleton);
container.RegisterType<ISecondSingleInstance, SecondSingleInstance>(Singleton);
return container;
}
private static ContainerControlledLifetimeManager Singleton =>
new ContainerControlledLifetimeManager();
}
public interface ISecondSingleInstance
{
void DoThisToo();
}
public interface IFirstSingleInstance
{
void DoThis();
}
public class FirstSingleInstance : IFirstSingleInstance
{
private ISecondSingleInstance _second;
public FirstSingleInstance(ISecondSingleInstance second)
{
_second = second;
}
public void DoThis()
{
System.Console.WriteLine("This Was Done.");
_second.DoThisToo();
}
}
public class SecondSingleInstance : ISecondSingleInstance
{
public SecondSingleInstance(/* other dependencies here */)
{
}
public void DoThisToo()
{
System.Console.WriteLine("This Was Done too.");
}
}