Project-Embedded IoC Container

2019-06-19 02:31发布

问题:

I am looking for a really simple and lightweight IoC Container whose C# source can be included in my own project (thus not making an external reference).

The reason for this is that I am writing an infrastructure and would like to provide a single .dll file, without any additional dependencies.

I also do not want to ILMerge my assembly with the IoC assembly..

I thought about MEF, some other suggestions?

回答1:

If you're using .NET 4.0 you have MEF included.

For .NET 2 I once wrote something similar using interfaces and Reflection. There are a lot of tutorials out there describing that process. Even if you can use MEF, its still worth attempting some reflection tutorials as this is how MEF works underneath.

Also check out this question which has some good answers. TinyIoC looks like its just a single source file.



回答2:

If you don't need anything fancy, a DI container can be really short:

public class Container
{
   private readonly Dictionary<Type,Func<Container,object>> factories;
   private readonly Dictionary<Type,object> cache;

   public Container()
   {
       this.factories = new Dictionary<Type,Func<Container,object>>();
       this.cache = new Dictionary<Type,object>();
   }

   public void Register<TContract>(Func<Container,TContract> factory)
   {
       // wrap in lambda which returns object instead of TContract
       factories[typeof(TContract)] = c => factory(c);
   }

   public TContract Get<TContract>()
   {
       var contract = typeof(TContract);
       if (!cache.ContainsKey(contract))
       {
           this.cache[contract] = this.factories[contract](this);
       }
       return (TContract)this.cache[contract];
   }
}

Which you would use like this:

var container = new Container();
container.Register<ICar>(c => new Car(
    c.Get<IEngine>(), c.Get<IWheel>()));
container.Register<IWheel>(c => new Wheel());
container.Register<IEngine>(c => new Engine());

var car = container.Get<ICar>();

Even more minimalistic would be to do dependency injection without a container:

IWheel wheel = new Wheel();
IEngine engine = new Engine();
ICar car = new Car(engine, wheel);

However, for complex object graphs it can quickly get complicated to maintain the correct construction order during refactorings. The container doesn't have this problem.



回答3:

I very much like Castle.Windsor which is open source, so you could add the relevant code files to your project



回答4:

It's not really that difficult to roll your own container, depending on the type of features you need. It is however very easy to create leaks when doing so, so I guess that you would probably want to use a tested-and-tried solution.

MEF is used by some as a container but (notable) others say that MEF is not an IOC container, in essence MEF was designed to be a plugin architecture not a dependency injection container.

Considering all this, I would recommend you either embed the full source code for the container of your choice in your application or use a tool to merge it's assembly into your own. ILMerge is a tool that could do that, most commercial obfuscators can help you do this as well. If you're building a commercial library or application I would definitely recommend using a proper obfuscator anyway.