C# 将IoC容器抽象到一个单例后面-做错了吗?

C# 将IoC容器抽象到一个单例后面-做错了吗?,c#,singleton,inversion-of-control,C#,Singleton,Inversion Of Control,通常,我喜欢让应用程序完全不知道IoC容器。但是,我遇到了需要访问它的问题。为了消除痛苦,我使用了一个基本的单例。在你跑向山丘或拔出猎枪之前,让我先看看我的解决方案。基本上,IoC单例完全不做任何事情,它只是委托给一个必须传入的内部接口。我发现这样做可以减轻单身人士的痛苦 以下是IoC包装: public static class IoC { private static IDependencyResolver inner; public static

通常,我喜欢让应用程序完全不知道IoC容器。但是,我遇到了需要访问它的问题。为了消除痛苦,我使用了一个基本的单例。在你跑向山丘或拔出猎枪之前,让我先看看我的解决方案。基本上,IoC单例完全不做任何事情,它只是委托给一个必须传入的内部接口。我发现这样做可以减轻单身人士的痛苦

以下是IoC包装:

public static class IoC
    {
        private static IDependencyResolver inner;

        public static void InitWith(IDependencyResolver container)
        {
            inner = container;
        }

        /// <exception cref="InvalidOperationException">Container has not been initialized.   Please supply an instance if IWindsorContainer.</exception>
        public static T Resolve<T>()
        {
            if ( inner == null)
                throw new InvalidOperationException("Container has not been initialized.  Please supply an instance if IWindsorContainer.");

            return inner.Resolve<T>();
        }

        public static T[] ResolveAll<T>()
        {
            return inner.ResolveAll<T>();
        }
    }
公共静态类IoC
{
私有静态IDependencyResolver内部;
公共静态void InitWith(IDependencyResolver容器)
{
内部=容器;
}
///容器尚未初始化。如果IWindsorContainer,请提供一个实例。
公共静态T解析()
{
if(内部==null)
抛出新的InvalidOperationException(“容器尚未初始化。如果IWindsorContainer.”,请提供一个实例);
返回inner.Resolve();
}
公共静态T[]ResolveAll()
{
返回inner.ResolveAll();
}
}
IDependencyResolver:

public interface IDependencyResolver
    {
        T Resolve<T>();
        T[] ResolveAll<T>();
    }
公共接口IDependencyResolver
{
T解析();
T[]ResolveAll();
}
到目前为止,我已经成功地使用了几次它(可能每隔几个项目就使用一次,我真的不想使用它),因为我可以注入任何我想要的东西:Castle、Stub、fakes等等


这条路滑吗?我会遇到潜在的问题吗

那不是一个真正的单身班。这是一个包含静态成员的静态类。是的,这似乎是一个好办法


我认为JP Boodhoo甚至对这种模式有一个名字

请注意:Microsoft模式和实践已经创建了一个公共服务定位器(),大多数主要的IoC容器都将在不久的将来实现它。您可以开始使用它而不是IDependencyResolver


顺便说一句:这是解决您的问题的常用方法,而且效果很好。

我已经看到,即使是Ayende也在Rhino Commons代码中实现了这种模式,但我建议尽可能不要使用它。在默认情况下,Castle Windsor没有此代码是有原因的。StructureMap有,但Jeremy Miller一直在远离它。理想情况下,您应该像对待任何全局变量一样对容器本身充满怀疑


但是,作为替代方案,您可以始终将容器配置为将IDependencyResolver解析为对容器的引用。这听起来可能很疯狂,但它要灵活得多。只要记住一条经验法则,对象应该调用“new”或执行处理,但不能同时执行这两种操作。对于“call new”,请替换为“resolve a reference”。

这取决于用法。使用这样的容器称为服务定位器模式。有些情况下,它并不适合,有些情况下,它确实适用

如果你用谷歌搜索“服务定位器模式”,你会看到很多博客帖子说这是一种反模式,而事实并非如此。这种模式只是被过度使用(/滥用)

对于典型的业务线应用程序,在隐藏依赖项时不应使用SL。您还遇到了另一个问题:如果使用根容器(而不是它的一个生存期),则无法管理状态/生存期

对于基础架构,服务定位器非常适合。例如,ASP.NET MVC使用服务定位器来解决每个控制器的所有依赖关系