如何解耦 IoC 框架实现

发布于 2024-12-25 04:17:16 字数 290 浏览 4 评论 0原文

我一直在学习 IoC、依赖注入等并享受这个过程。对我来说,解耦和接口编程的好处是显而易见的。

然而,我真的不喜欢将自己绑定到 Unity、Autofac 或 Windsor 等特定框架 - 因为我仍在学习,尚未决定哪个最适合我的目的。

那么,我该如何包装像 Unity 这样的东西,以便以后可以轻松地交换到 Windsor 中呢? (或其他什么)。而且你不敢说用另一个来注入第一个;)

谢谢!

R.

Ps 我标记 Unity 是因为这是我目前的个人偏好(我只是迷恋 Entlib)。

I've been learning IoC, Dependency Injection etc. and enjoying the process. The benefits of decoupling and programming to interfaces are, to me, a no-brainer.

However, I really don't like binding myself to a specific framework like Unity or Autofac or Windsor - because I'm still learning and haven't yet decided which is best for my purposes.

So, how can I wrap around something like Unity so I could easily swap in Windsor at a later date? (or whatever). And don't you dare say use another one to inject the first one ;)

Thanks!

R.

P.s. I tagged Unity as that's my current personal preference (I just lurve Entlib).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

古镇旧梦 2025-01-01 04:17:16

您当然可以尝试通过使用 ResolveRegister 声明 IContainer 来从容器中进行抽象。我这样做过几次。然后,您将继续实现一个 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 撰写。

是的,他们抽象了控制反转容器。我认为,如果您需要这样做,那么很明显您并没有真正了解 IoC 的全部内容。

You can certainly try making an abstraction from the container by declaring an IContainer with say Resolve and Register. I did that a couple of times. Then you would go ahead and implement a Container : IContainer and encapsulate an actual IoC container with your abstraction. I tried that with Unity and Castle Windsor.

But hey, soon I realised that this was really an over-engineering. I then understood that I tried to abstract from abstraction, yet to build another abstraction. This could be fine to learn the concept, but it was a real pain in the neck in a real project. I would highly recommend against an abstraction from IoC container. If you correctly use DI principle it will be fairly easy to change your container anyways.

The code looks overcomplicated, like

//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

See this post by Ayende.

Yes, they abstracted the Inversion of Control Container. I think that if you need to do that, it is pretty clear that you don’t really get what IoC is all about.

走走停停 2025-01-01 04:17:16

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

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

Use constructor injection to communicate what dependencies a class needs. Every container you listed supports it.

Sometimes a piece of code cannot achieve complete container independence, but these cases should be a very small part of your codebase.

喵星人汪星人 2025-01-01 04:17:16

DI 容器只能从组合根引用。
所有其他模块不应引用该容器。

-Mark Seemann(.NET 中的依赖注入一书的作者)

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

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

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

A DI Container should only be referenced from the Composition Root.
All other modules should have no reference to the container.

-Mark Seemann (author of Dependency Injection in .NET)

In other words, you should only need to change one class if you change DI containers.

Constructor injection is normally the right way to go, as others have mentioned. You can inject factory interfaces or Func<T> delegates if you need to create objects on the fly.

I'd also suggest avoiding XML configuration whenever possible.

清泪尽 2025-01-01 04:17:16

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

如果您的类直接依赖于 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 接口(根据 接口隔离原则)。

As some other folks have mentioned, prefer constructor injection. This will solve many of your problems.

If your classes have direct dependencies on the IoC container itself, it tends to be a variant of using the service locator (anti-)pattern. In this particular case, isolate which types are being resolved via the service locator, and abstract that dynamic resolution with a factory interface. So, for instance, replace this:

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

with this:

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

Now, you have an IObjFactory that can encapsulate the dynamic, runtime nature of constructing objects that implement ISomeType. If you are constructing many different types of object from the container/service locator, then you should have at least as many *Factory interfaces (in accordance with the Interface Segregation Principle).

月竹挽风 2025-01-01 04:17:16

查看通用服务定位器库 (github)。 (之前位于 CodePlex)。

Check out the Common Service Locator library (github). (Previously located on CodePlex).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文