开发者

Unity .NET: List of dependencies

Is it possible to inject a list of dependencies like this in Unity or other kind of IoC libraries?

public class Crawler 
{
    public Crawler(IEnumerable<IParser> parsers) 
    {
         // init here...
    }
}

In this way I can register multiple IParser in my container and then开发者_如何学JAVA resolve them.

Is it possible? Thanks


It is possible but you need to apply some workarounds. First you need to register each IParser with a name in the Unity Container. Second you need to register a mapping from IParser[] to IEnumerable<IParser> in the container. Otherwise the container cannot inject the parsers to the constructor. Here´s how i have done it before.

IUnityContainer container = new UnityContainer();

container.RegisterType<IParser, SuperParser>("SuperParser");
container.RegisterType<IParser, DefaultParser>("DefaultParser");
container.RegisterType<IParser, BasicParser>("BasicParser");
container.RegisterType<IEnumerable<IParser>, IParser[]>();
container.RegisterType<Crawler>();

Crawler crawler = container.Resolve<Crawler>();

I have discarded this solution by introducing a factory, that encapsulates unity to construct the needed types. Here´s how i would do it in your case.

public interface IParserFactory{
  IEnumerable<IParser> BuildParsers();
}

public class UnityParserFactory : IParserFactory {
  private IUnityContainer _container;

  public UnityParserFactory(IUnityContainer container){
    _container = container;
  }

  public IEnumerable<IParser> BuildParsers() {
    return _container.ResolveAll<IParser>();
  }
}

public class Crawler {
  public Crawler(IParserFactory parserFactory) {
     // init here...
  }
}

With this you can register the types as follows:

IUnityContainer container = new UnityContainer();

container.RegisterType<IParser, SuperParser>();
container.RegisterType<IParser, DefaultParser>();
container.RegisterType<IParser, BasicParser>();
container.RegisterType<IParserFactory, UnityParserFactory>();

Crawler crawler = container.Resolve<Crawler>();


Not that I'm saying it's wrong but it seems like you are trying to solve a plugin model that you could easily manage with the use of MEF instead. Hints would be inherited Export from the interface and then do ImportMany when you need the parsers.


There are ways to achieve this in Unity. For example,

http://sharpsnmplib.codeplex.com/SourceControl/changeset/view/5497af31d15e#snmpd%2fapp.config

    <register type="UserRegistry">
      <lifetime type="singleton" />
      <constructor>
        <param name="users" dependencyType="User[]" />
      </constructor>
    </register>

This constructor requires an array of User objects, and all such objects defined in this container are injected by Unity into it when the UserRegistry object is created.


As a matter of fact, I don't know any container that does not support this.

However, as a general advice, you should prevent injecting lists of services into consumers if you can, by wrapping that list in a composite, and inject that composite into consumers. Not wrapping the list in a composite would clutter the application with extra foreach loops or what ever you need to do to process that list of dependencies. While this doesn't seem bad, the consumers of these dependencies shouldn't care. But worse, when we want to change the way the list of services is handled, we will have to go through the complete application, which is a violation of the DRY principle.

This advice does not hold when the consumer (in your case the Crawler) is part of the Composition Root instead of the application itself. Further more, when the application only has a single consumer that takes this dependency, it might not be that big of deal.


yes you can.. you can look at dependency injectors. I am a big fan of the Autofac project.

Another option is Ninject,

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜