2017-09-23 45 views
0

我有一个完整的(和破碎的)C#应用程序下面,生成堆栈溢出异常。如果您查看源代码,您将看到为什么会有堆栈溢出异常,所以我没有真正考虑诊断为什么会发生这种情况,我想知道处理它的最佳方式是什么。什么是在Unity容器上调用dispose的最佳方式?

1)所有对unity的引用都封装在一个名为Registry的类中,所以我可以毫无困难地进行升级。我不希望unitycontainer在可能的情况下丢弃其他类。从理论上讲,如果出现这种情况,我应该可以升级到5,或者如果我的性格发生了剧烈的变化,甚至可以将它与ninject或其他DI框架互换。

2)我想注册表由统一容器控制,以便它可以在容器控制类的构造函数中使用。 (例如FirstSingleInstance)

3)IRegistry和Registry从IDisposable继承,因为我认为这是处理统一容器的好习惯。

4)注册表在它自己的构造函数中构造了Unity容器,所以我假设我应该在调用registry.dispose时处理统一容器。 5)所有其他由Registry控制的类都应该是单实例类,所以我使用ContainerControlledLifetimeManager注册它们。我预计这些实例将在集装箱处置时处置。

处理这种情况的最佳做法是什么?

a)不要在注册表中调用dispose - 让它为进程线程的生命而生存?

b)不要试图让统一容器控制注册表(以及扩展名,UnityContainer)。这种在Registry上调用dispose的方式不会导致stackoverflow异常。然后,我会如何构建FirstSingleInstance类,这是我必须审查的。

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

感谢您的任何帮助出路似乎是合理的。

+0

那么为什么你在容器中注册'IRegistry'? – Steven

+0

因为FirstSingleInstance类将其作为公共构造函数中的参数接受。 – Jason

+0

为什么它需要它作为依赖项?我可以想象它需要容器,但不是注册表,它基本上是你的组合根。 – Steven

回答

1

以下代码禁止使用Service Locator anti-pattern,而是完全依赖构造函数注入作为应用控制反转的模式。结果是一个更简单,更易维护且更易测试的应用程序,不会导致任何计算器溢出异常。

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."); 
    } 
} 
+1

这非常简单。谢谢Steven! – Jason

+0

顺便说一句,似乎你刚开始使用DI容器。在这种情况下,Unity可能不是您的最佳选择,因为1)与其他DI容器相比,它在功能上落后了许多年,2)Microsoft [stopped](https://blogs.msdn.microsoft.com/dotnet/2015/08/21/the-future-of-unity /)从2015年开始维护它,它是[最新版本](https://github.com/unitycontainer/unity/releases)是从2014年5月起。 – Steven

+0

你可能想要阅读关于DI的[一本好书](https://www.manning.com/seemann2/);-) – Steven

相关问题