如何解耦IoC框架实现

时间:2012-01-05 22:46:13

标签: c# dependency-injection inversion-of-control unity-container enterprise-library

我一直在学习IoC,依赖注入等,并享受这个过程。对我来说,解耦和编程接口的好处是不费吹灰之力的。

但是,我真的不喜欢将自己绑定到像Unity或Autofac或Windsor这样的特定框架 - 因为我还在学习并且还没有确定哪个最适合我的目的。

那么,我怎样才能将Unity这样的东西包裹起来,这样我以后就可以轻松换掉温莎呢? (管他呢)。并且你不敢说使用另一个注入第一个;)

谢谢!

R上。

P.S。我将Unity标记为我当前的个人偏好(我只是在使用Entlib)。

5 个答案:

答案 0 :(得分:18)

使用构造函数注入来传达类所需的依赖项。您列出的每个容器都支持它。

有时一段代码无法实现完全的容器独立性,但这些情况应该只是代码库的一小部分。

答案 1 :(得分:18)

您当然可以尝试通过声明IContainer ResolveRegister来宣传容器中的抽象。我这样做了几次。然后,您将继续实现 Container:IContainer ,并使用您的抽象封装实际的IoC容器。我和Unity和Castle Windsor一起试过了。

但是,嘿,我很快意识到这真的是一种过度工程。然后我明白我试图从抽象中抽象出来,然后构建另一个抽象。这可以很好地学习这个概念,但在真正的项目中,这是一个真正的痛苦。我强烈建议不要从IoC容器中抽象出来。如果您正确使用DI原则,无论如何都可以很容易地更换容器。

代码看起来过于复杂,比如

//I did this mess with Service Locator
var t = ContainerService.Instance.Resolve<IMyType>();
//others could go further with same Service Locator
var t = IoCFactory.Instance.CurrentContainer.Resolve<IMyType>();

//better way, use --> IoC and DI <--
//when a program starts, or a new instance of the context created
var t = Container.Resolve<IMyType>() //this lives at the bottom of the stack
//and then you just pass IMyType to the constructor of other types    
//you don't need to call Resolve again in the logical cycle

见Ayende的this post

  

是的,他们抽象了反转控制容器。我认为如果你需要这样做,很明显你真的没有得到IoC的全部内容。

答案 2 :(得分:9)

  

DI容器只能从Composition Root引用。   所有其他模块都不应该引用容器。

-Mark Seemann(Dependency Injection in .NET的作者)

换句话说,如果更改DI容器,则只需要更改一个类。

正如其他人所提到的,构造函数注入通常是正确的方法。如果需要动态创建对象,可以注入工厂接口或Func<T>代理。

我还建议尽可能避免使用XML配置。

答案 3 :(得分:4)

正如其他人提到的那样,更喜欢构造函数注入。这将解决您的许多问题。

如果您的类直接依赖于IoC容器本身,则它往往是使用服务定位器(反)模式的变体。在这种特殊情况下,隔离通过服务定位器解析哪些类型,并使用工厂接口抽象该动态解析。所以,例如,替换这个:

public class Foo
{
    private MyIoCContainer _container;

    public Foo(MyIoCContainer container)
    {
        this._container = container;
    }


    public void DoSomething()
    {
        // have to do this at runtime for whatever reason
        var myObj = this._container.Resolve<ISomeType>();

        myObj.DoSomething();
        myObj.DoSomethingElse();
    }
}

用这个:

public class Foo
{
    private IObjFactory _provider;

    public Foo(IObjFactory _provider)
    {
        this._provider = provider;
    }


    public void DoSomething()
    {
        var myObj = _provider.GetObj();

        myObj.DoSomething();
        myObj.DoSomethingElse();
    }
}

public interface IObjFactory
{
    ISomeType GetObj();
}

现在,您有一个IObjFactory可以封装构造实现ISomeType的对象的动态,运行时性质。如果要从容器/服务定位器构造许多不同类型的对象,那么您应该至少有*Factory个接口(根据Interface Segregation Principle)。

答案 4 :(得分:3)

查看Common Service Locator库(github)。 (以前位于CodePlex)。