Abstracting IoC Container Behind a Singleton - Doi

2019-02-02 02:58发布

Generally, I like to keep an application completely ignorant of the IoC container. However I have ran into problems where I needed to access it. To abstract away the pain I use a basic Singleton. Before you run for the hills or pull out the shotgun, let me go over my solution. Basically, the IoC singleton does absolutly nothing, it simply delegates to an internal interface that must be passed in. I've found this makes working with the Singleton less painful.

Below is the IoC wrapper:

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

IDependencyResolver:

public interface IDependencyResolver
    {
        T Resolve<T>();
        T[] ResolveAll<T>();
    }

I've had great success so far with the few times I've used it (maybe once every few projects, I really prefer not having to use this at all) as I can inject anything I want: Castle, a Stub, fakes, etc.

Is this a slippery road? Am I going to run into potential issues down the road?

4条回答
该账号已被封号
2楼-- · 2019-02-02 03:08

I've seen that even Ayende implements this pattern in the Rhino Commons code, but I'd advise against using it wherever possible. There's a reason Castle Windsor doesn't have this code by default. StructureMap does, but Jeremy Miller has been moving away from it. Ideally, you should regard the container itself with as much suspicion as any global variable.

However, as an alternative, you could always configure your container to resolve IDependencyResolver as a reference to your container. This may sound crazy, but it's significantly more flexible. Just remember the rule of thumb that an object should call "new" or perform processing, but not both. For "call new" replace with "resolve a reference".

查看更多
Melony?
3楼-- · 2019-02-02 03:13

Just a note: Microsoft Patterns and Practices has created a common service locator (http://www.codeplex.com/CommonServiceLocator) that most of the major IoC containers will be implementing in the near future. You can begin to use it instead of your IDependencyResolver.

BTW: this is the common way to solve your problem and it works quite well.

查看更多
放我归山
4楼-- · 2019-02-02 03:14

That's not really a singleton class. That's a static class with static members. And yes that seems a good approach.

I think JP Boodhoo even has a name for this pattern. The Static Gateway pattern.

查看更多
迷人小祖宗
5楼-- · 2019-02-02 03:17

It all depends on the usage. Using the container like that is called the Service Locator Pattern. There are cases where it's not a good fit and cases where it do apply.

If you google "service locator pattern" you'll see a lot of blog posts saying that it's an anti-pattern, which it's not. The pattern has simply been overused (/abused).

For typical line of business applications you should not use SL as you hide the dependencies. You also got another problem: You can not manage state/lifetime if you use the root container (instead of one of it's lifetimes).

Service locator is a good fit when it comes to infrastructure. For instance ASP.NET MVC uses Service Locator to be able to resolve all dependencies for each controller.

查看更多
登录 后发表回答