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

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

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

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


当前回答

在。net世界里AOP还不是很流行,所以对于依赖注入来说,一个框架是你唯一真正的选择,不管你是自己写一个框架还是使用另一个框架。

如果您使用AOP,则可以在编译应用程序时进行注入,这在Java中更为常见。

DI有很多好处,比如减少耦合,从而使单元测试更容易,但是您将如何实现它呢?你想用反射来自己做吗?

其他回答

对我来说,使用IoC容器的最大好处(我个人使用Ninject)是消除了设置和其他类型的全局状态对象的传递。

我不为web编程,我的是一个控制台应用程序,在对象树的许多地方,我需要访问用户指定的设置或元数据,这些设置或元数据是在对象树的一个完全独立的分支上创建的。通过IoC,我简单地告诉Ninject将设置作为一个单例(因为它们总是只有一个实例),在构造函数中请求设置或字典,然后立即…它们在我需要的时候神奇地出现了!

如果不使用IoC容器,我将不得不通过2,3,…传递设置和/或元数据。在它被需要它的对象实际使用之前,有n个对象。

DI/IoC容器还有许多其他好处,正如其他人在这里详细介绍的那样,从创建对象到请求对象的想法可能会令人难以置信,但使用DI对我和我的团队非常有帮助,所以也许您可以将其添加到您的库中!

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容器配置模块替换了一个工厂实现。

老实说,我没有发现有很多情况需要IoC容器,大多数情况下,它们只是增加了不必要的复杂性。

如果你只是用它来简化对象的构造,我要问,你是否在多个位置实例化了这个对象?单例不适合您的需要吗?您是否在运行时更改配置?(切换数据源类型等)。

如果是,那么您可能需要一个IoC容器。如果不是,那么您只是将初始化移到开发人员容易看到的地方。

谁说接口比继承好?假设您正在测试一个服务。为什么不使用构造函数DI,并使用继承创建依赖关系的模拟呢?我使用的大多数服务只有少数依赖项。以这种方式进行单元测试可以避免维护大量无用的接口,也意味着您不必使用Resharper来快速查找方法的声明。

我相信对于大多数实现来说,说IoC容器删除不需要的代码是一个神话。

首先,首先要设置容器。然后,您仍然必须定义需要初始化的每个对象。所以在初始化时不保存代码,而是移动它(除非你的对象被使用了不止一次)。单例是否更好?)然后,对于以这种方式初始化的每个对象,都必须创建和维护一个接口。

有人有什么想法吗?

我认为IoC的大部分价值都是通过使用DI获得的。既然你已经这样做了,剩下的好处是递增的。

你得到的值将取决于你正在处理的应用程序的类型:

For multi-tenant, the IoC container can take care of some of the infrastructure code for loading different client resources. When you need a component that is client specific, use a custom selector to do handle the logic and don't worry about it from your client code. You can certainly build this yourself but here's an example of how an IoC can help. With many points of extensibility, the IoC can be used to load components from configuration. This is a common thing to build but tools are provided by the container. If you want to use AOP for some cross-cutting concerns, the IoC provides hooks to intercept method invocations. This is less commonly done ad-hoc on projects but the IoC makes it easier.

我以前写过这样的功能,但如果我现在需要这些功能中的任何一个,我宁愿使用一个预先构建并经过测试的工具,如果它适合我的架构的话。

正如其他人所提到的,您还可以集中配置希望使用的类。虽然这可能是一件好事,但代价是误导和复杂化。大多数应用程序的核心组件都没有被替换,因此很难做出取舍。

我使用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.