C# 使用国际奥委会集装箱;特别是温莎

C# 使用国际奥委会集装箱;特别是温莎,c#,inversion-of-control,castle-windsor,C#,Inversion Of Control,Castle Windsor,我认为这个问题的答案是如此的令人生畏,以至于没有人费心写这篇文章,但是已经很晚了,我真的无法理解这一点 我一直在阅读IoC容器(本例中为Windsor),但我不知道如何从代码的各个部分与容器对话 我得到了DI,我已经做了一段时间可怜的mans DI(空构造函数调用带有默认参数实现的重载注入构造函数),我完全可以看到容器的好处。然而,我遗漏了一条重要的信息;每次需要容器提供服务时,如何引用容器 我是否创造了一个我传递的全球疯狂?当然不是 我知道我应该称之为: WindsorContainer co

我认为这个问题的答案是如此的令人生畏,以至于没有人费心写这篇文章,但是已经很晚了,我真的无法理解这一点

我一直在阅读IoC容器(本例中为Windsor),但我不知道如何从代码的各个部分与容器对话

我得到了DI,我已经做了一段时间可怜的mans DI(空构造函数调用带有默认参数实现的重载注入构造函数),我完全可以看到容器的好处。然而,我遗漏了一条重要的信息;每次需要容器提供服务时,如何引用容器

我是否创造了一个我传递的全球疯狂?当然不是

我知道我应该称之为:

WindsorContainer container = new WindsorContainer(new XmlInterpreter());
(例如)当我想加载我的XML配置时,我该如何处理容器?是否每次创建一个新的容器之后都会通过一些内部静态majicks或其他方式保存加载的配置,或者每次都必须重新加载配置(我想不会,或者生命周期无法工作)

如果不理解这一点,我就无法了解生命周期是如何工作的,也无法继续使用一些令人讨厌的东西

谢谢


Andrew

我正在使用此接口的实现:

public interface IResolver
{
    object Resolve(Type type);
    object Resolve(string name);

    T Resolve<T>() where T : class;
    T Resolve<T>(string name) where T : class;
}
公共接口IResolver
{
对象解析(类型);
对象解析(字符串名称);
T Resolve(),其中T:class;
T解析(字符串名称),其中T:class;
}
它实际上被包装在全局静态类中,例如:

public static class Resolver // : IResolver
{
    private static IResolver _current;

    public static object Resolve(Type type)
    {
        return Current.Resolve(type);
    }

    public static object Resolve(string name)
    {
        return Current.Resolve(name);
    }

    public static T Resolve<T>() where T : class
    {
        return Current.Resolve<T>();
    }

    public static T Resolve<T>(string name) where T : class
    {
        return Current.Resolve<T>(name);
    }

    private static IResolver Current
    {
        get
        {
            if (_current == null)
            {
                _current = new SpringResolver();
            }

            return _current;
        }
    }
}
公共静态类解析器//:IResolver
{
专用静态IResolver\u电流;
公共静态对象解析(类型)
{
返回当前解析(类型);
}
公共静态对象解析(字符串名称)
{
返回当前解析(名称);
}
公共静态T Resolve(),其中T:class
{
返回Current.Resolve();
}
公共静态T解析(字符串名称),其中T:class
{
返回当前解析(名称);
}
专用静态电流解算器
{
得到
{
如果(_current==null)
{
_当前=新的SpringResolver();
}
返回电流;
}
}
}

此外,我还尝试遵循简单的规则-尽可能少地使用解析器类,而是在需要这些服务的对象中注入服务。

99%的情况下,每个应用程序只有一个容器实例。通常在应用程序启动(对于web应用程序)中对其进行初始化

在那之后,这实际上取决于容器的消费者。例如,一些框架,如和,允许您拦截实例(本例中为控制器)的创建,因此您只需在容器中注册控制器及其依赖项,即当您收到请求时,容器会负责向每个控制器注入其依赖项。例如,见。 在这些框架中,您几乎不需要调用甚至引用类中的容器,这是推荐的用法

其他框架不允许您轻松地进入创建过程(如Webforms),因此您必须求助于黑客攻击,例如,或提取所需的依赖项(即显式调用容器)。要提取依赖项,请使用容器的静态网关,如或所述。请注意,通过这样做,您实际上将容器用作服务定位器,这既不会使事情解耦,也不会使控制反转。(见差异和差异)


希望这能消除您的疑虑。

我使用Michael Puleio的博客中的这个例子,介绍如何使用HttpModule来处理使用Unity建立的依赖关系

通常,您希望在整个应用程序的生命周期中只保留一个实例。
大多数时候,我所做的是在应用程序启动时初始化容器,然后使用类型化工厂对对象进行容器抽取


另一种流行的方法是使用静态类包装容器实例,并使用该静态类访问(单例)容器。你可以在Ayende的Rhino.Commons库中找到一个例子。然而,这种方法有严重的缺点,应该避免。

正如这里的其他答案所述,有很多选择,同样,我们要自己找出在我们的情况下最好的方法


这就是说,IMO拥有一个可在整个应用程序中访问的全局容器在某种程度上打破了隔离,因为现在很多代码都依赖于一个全局类。此外,对于拆分为多个程序集的应用程序,必须使所有这些程序集都可以访问全局容器

使用,您可以在构造函数中实际拥有一个IUnityContainer参数,当您解析该类时,容器将自动将自身注入实例中。这样,对于需要解析容器中传递的其他服务的服务,而不是强制类引用外部类


不确定其他框架如何支持此场景(Windsor将注入
IKernel
)。

“对于拆分为多个程序集的应用程序,必须使所有这些程序集都可以访问全局容器。”不,任何IoC容器的一个要点都是非侵入性的。温莎和其他人实现并推荐了这一点。@mausch-当人们普遍建议使用共享的单例容器时,它是如何实现的?还是我的假设错了?我看不出我的回答与国际奥委会的观点有什么矛盾。这让人觉得侵入式的是如何使用IoC框架,而不是框架本身。是的,只有一个容器,但除了启动代码和一些特定的粘合代码(如ASP.NET MVC ControllerFactory)之外,没有人应该知道它。否则,这不是依赖注入和控制反转,而是服务位置。看,我不得不说,我是新来的t