Unity .NET: List of dependencies

北城余情 提交于 2019-12-09 16:12:14

问题


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 resolve them.

Is it possible? Thanks


回答1:


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



回答2:


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.




回答3:


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.




回答4:


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.




回答5:


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

Another option is Ninject,



来源:https://stackoverflow.com/questions/7483308/unity-net-list-of-dependencies

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!