我已经使用依赖注入(DI)有一段时间了,在构造函数、属性或方法中进行注入。我从未觉得有必要使用反转控制(IoC)容器。然而,我读得越多,我就越感到来自社区的使用IoC容器的压力。

我使用过StructureMap、NInject、Unity和Funq等。net容器。我仍然没有看到IoC容器将如何受益/改进我的代码。

我也害怕在工作中开始使用容器,因为我的许多同事会看到他们不理解的代码。他们中的许多人可能不愿意学习新技术。

请说服我,我需要使用IoC容器。当我在工作中与其他开发人员交谈时,我将使用这些论点。


当前回答

依赖注入在ASP。NET项目可以用几行代码完成。我认为,当你的应用程序使用多个前端并需要单元测试时,使用容器会有一些好处。

其他回答

我只是碰巧正在把自己生长的DI代码拉出来,并用IOC替换它。我可能已经删除了200多行代码,用大约10行代码替换了它。是的,我必须学习如何使用容器(Winsor),但我是一名在21世纪从事互联网技术工作的工程师,所以我已经习惯了。我大概花了20分钟看了一下怎么做。这很值得我花时间。

我知道这是一个相当老的帖子,但它似乎仍然相当活跃,我想我可以贡献一些在其他回答中没有提到的观点。

我同意依赖注入的好处,但我更喜欢自己构造和管理对象,使用与Maxm007在回答中概述的模式相似的模式。我发现了使用第三方容器的两个主要问题:

1) Having a 3rd party library manage the lifetime of your objects "automagically" can lend itself to unexpected results. We have found that especially in large projects, you can have vastly more copies of an object than you expect, and more than you would if you were manually managing the lifecycles. I'm sure this varies depending on the framework used, but the problem exists nonetheless. This can also be problematic if your object holds resources, data connections, etc., since the object can sometimes live longer than you expect. So inevitably, IoC containers tend to increase the resource utilization and memory footprint of an application.

2) IoC containers, in my opinion, are a form of "black box programming". I have found that in particular, our less experienced developers tend to abuse them. It allows the programmer to not have to think about how objects should relate to each other or how to decouple them, because it provides them with a mechanism in which they can simply grab any object they want out of thin air. Eg, there may be a good design reason that ObjectA should never know about ObjectB directly, but rather than creating a factory or bridge or service locator, an inexperienced programmer will simply say "no problem, I'll just grab ObjectB from the IoC container". This can actually lead to increased object coupling, which is what IoC is supposed to help prevent.

不需要IoC容器。

但是如果您严格遵循依赖注入模式,您会发现使用一个依赖注入模式将会删除大量冗余的、无聊的代码。

无论如何,这通常是使用一个库/框架的最佳时机——当你了解它在做什么并且不需要库也能完成它的时候。

我将尝试从我的角度找出为什么IOC可能不好。

As with everything else, IOC container (or as Einstein would put it I=OC^2) is a concept you have to decide for yourself if you need it or not in your code. Recent fashion outcry about IOC is only that, fashion. Don't fall for fashion, that is first. There are myriads of concepts out there you could implement in your code. First of all, I am using dependency injection since I have started programming, and learned the term itself when it was popularized under that name. Dependency control is a very old subject and it was addressed so far in trillions of ways, depending on what was decoupling from what. Decoupling everything from everything is a nonsense. The problem with IOC container is that it tries to be as useful as Entity Framework or NHibernate. While writing an object-relational mapper is simply a must as soon as you have to couple any database with your system, IOC container is not always necessary. So when IOC container is useful:

当你有很多依赖的情况,你想组织 当你不关心你的代码与第三方产品的耦合时 当您的开发人员想要学习如何使用新工具时

1:在你的代码中有这么多依赖关系并不常见,或者你在设计的早期就意识到了它们。当需要抽象思维时,抽象思维是有用的。

2:将你的代码与第三方代码耦合是一个巨大的问题。我使用的是10多年前的代码,当时遵循的是ATL、COM、COM+等花哨而先进的概念。现在你对这些代码无能为力了。我想说的是,一个先进的概念会带来明显的优势,但从长远来看,这种优势本身就过时了。这只会让一切都变得更贵。

3: Software development is hard enough. You can extend it to unrecognizable levels if you allow some advanced concept to crop into your code. There is a problem with IOC2. Although it is decoupling dependencies, it is decoupling the logic flow as well. Imagine you have found a bug and you need to set a break to examine the situation. IOC2, as any other advanced concept, is making that more difficult. Fixing a bug within a concept is more difficult than fixing a bug in a plainer code, because when you fix a bug a concept must be obeyed again. (Just to give you an example, C++ .NET is constantly changing the syntax so much that you need to think hard before you refactor some older version of .NET.) So what is the problem with IOC? The problem is in resolving dependencies. The logic for resolving is commonly hidden in the IOC2 itself, written maybe in uncommon way that you need to learn and maintain. Will your third-party product be there in 5 years? Microsoft's was not.

"We know how" syndrome is written all over the place regarding IOC2. This is similar to automation testing. Fancy term and perfect solution at first glance, you simply put all your tests to execute over night and see the results in the morning. It is really painful to explain company after company what automated testing really means. Automated testing is definitely not a quick way of reducing the number of bugs which you can introduce overnight to increase the quality of your product. But, fashion is making that notion annoyingly dominant. IOC2 suffers the same syndrome. It is believed that you need to implement it in order your software to be good. EvErY recent interview I was asked if I am implementing IOC2 and automation. That is a sign of fashion: the company had some part of code written in MFC they will not abandon.

你需要像学习软件中的其他概念一样学习IOC2。是否需要使用IOC2是由团队和公司内部决定的。但是,在做出决定之前,至少必须提到以上所有的理由。只有当你看到积极的一面超过消极的一面,你才能做出积极的决定。

There is nothing wrong with IOC2 except that it does solve only the problems it solves and introduces the problems it introduces. Nothing else. However, going against the fashion is very difficult, they have sweat mouth, the followers of anything. It is strange how none of them is there when the problem with their fanciness becomes apparent. Many concepts in software industry have been defended because they create profit, books are written, conferences held, new products made. That is fashion, usually short lived. As soon as people find something else they abandon it completely. IOC2 is useful but it shows the same signs as many other vanished concepts I have seen. I do not know if it will survive. There is no rule for that. You think if it is useful, it will survive. No, it does not go that way. One big rich company is enough and the concept can die within few weeks. We'll see. NHibernate survived, EF came second. Maybe IOC2 will survive too. Do not forget that most concepts in software development are about nothing special, they are very logical, simple and obvious, and sometimes it is more difficult to remember the current naming convention than to understand the concept itself. Does the knowledge of IOC2 make a developer a better developer? No, because if a developer was not able to come up with a concept similar in nature to IOC2 then it will be difficult for him or her to understand which problem IOC2 is solving, using it will look artificial and he or she may start using it for sake of being some sort of politically correct.

I'm a recovering IOC addict. I'm finding it hard to justify using IOC for DI in most cases these days. IOC containers sacrifice compile time checking and supposedly in return give you "easy" setup, complex lifetime management and on the fly discovering of dependencies at run time. I find the loss of compile time checking and resulting run time magic/exceptions, is not worth the bells and whistles in the vast majority of cases. In large enterprise applications they can make it very difficult to follow what is going on.

我不相信集中化的说法,因为你可以通过为你的应用程序使用一个抽象工厂,并虔诚地将对象创建推迟到抽象工厂,即进行适当的DI,来非常容易地集中静态设置。

为什么不像这样做静态无魔法DI:

interface IServiceA { }
interface IServiceB { }
class ServiceA : IServiceA { }
class ServiceB : IServiceB { }

class StubServiceA : IServiceA { }
class StubServiceB : IServiceB { }

interface IRoot { IMiddle Middle { get; set; } }
interface IMiddle { ILeaf Leaf { get; set; } }
interface ILeaf { }

class Root : IRoot
{
    public IMiddle Middle { get; set; }

    public Root(IMiddle middle)
    {
        Middle = middle;
    }

}

class Middle : IMiddle
{
    public ILeaf Leaf { get; set; }

    public Middle(ILeaf leaf)
    {
        Leaf = leaf;
    }
}

class Leaf : ILeaf
{
    IServiceA ServiceA { get; set; }
    IServiceB ServiceB { get; set; }

    public Leaf(IServiceA serviceA, IServiceB serviceB)
    {
        ServiceA = serviceA;
        ServiceB = serviceB;
    }
}


interface IApplicationFactory
{
    IRoot CreateRoot();
}

abstract class ApplicationAbstractFactory : IApplicationFactory
{
    protected abstract IServiceA ServiceA { get; }
    protected abstract IServiceB ServiceB { get; }

    protected IMiddle CreateMiddle()
    {
        return new Middle(CreateLeaf());
    }

    protected ILeaf CreateLeaf()
    {
        return new Leaf(ServiceA,ServiceB);
    }


    public IRoot CreateRoot()
    {
        return new Root(CreateMiddle());
    }
}

class ProductionApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new ServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new ServiceB(); }
    }
}

class FunctionalTestsApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new StubServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new StubServiceB(); }
    }
}


namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            var factory = new ProductionApplication();
            var root = factory.CreateRoot();

        }
    }

    //[TestFixture]
    class FunctionalTests
    {
        //[Test]
        public void Test()
        {
            var factory = new FunctionalTestsApplication();
            var root = factory.CreateRoot();
        }
    }
}

容器配置是抽象工厂实现,注册是抽象成员的实现。 如果您需要一个新的单例依赖项,只需向抽象工厂添加另一个抽象属性即可。如果你需要一个瞬态依赖,只需添加另一个方法并将其作为Func<>注入即可。

优点:

所有的设置和对象创建配置都是集中的。 配置只是代码 编译时检查使其易于维护,因为您不会忘记更新注册。 没有运行时反射魔法

我建议持怀疑态度的人尝试下一个新项目,诚实地问问自己什么时候需要这种容器。稍后很容易引入IOC容器,因为您只是用IOC容器配置模块替换了一个工厂实现。