如何注册一个以`Func<>`作为参数的类?

时间:2012-03-22 12:32:24

标签: c# dependency-injection unity-container

我有以下代码:

_container = new UnityContainer();
_container.RegisterType<IDownloader, Downloader>();
_container.RegisterType<INewObject, NewObject>();
_container.RegisterType<SearchViewModel>();
带构造函数注入的

SearchViewModel类:

class SearchViewModel
{
    private readonly Func<IDownloader> _downloaderFactory;
    private readonly INewObject _newObject;
    private IDownloader _downloader;

    public SearchViewModel(Func<IDownloader> downloaderFactory, INewObject newObject)
    {
        _downloaderFactory = downloaderFactory;
        _newObject = newObject;
    }        
}

问题:如何注册SearchViewModel作为参数的Fun<>

_container.RegisterType<SearchViewModel>(new InjectionConstructor(DownloaderFactory()));

上述代码仅适用于INewObject

目标:使用InjectionConstructor解析工厂并自动解决INewObject, INewObject2, INewObject3(例如不带参数:RegisterType<SearchViewModel>())。

有可能吗?也许是替补?

2 个答案:

答案 0 :(得分:10)

我已经解决了这个问题:

_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i => 
            new Func<IDownloader> (() => _container.Resolve<IDownloader>())));
_container.RegisterType<SearchViewModel>();

新的Func是关键,因为在我尝试之前:

_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i => 
            _container.Resolve<IDownloader>()));

使用IDownloaderFactory代替Func<IDownloader> downloaderFactory的更好方法。 IDownloaderFactory可以封装委托。

另外我认为使用委托作为工厂内的依赖是比破坏的Composition Root更好的解决方案。

答案 1 :(得分:3)

这里使用的普遍接受的模式是声明一个抽象工厂并使其更明确:

 public interface IDownloaderFactory
 {
    IDownloader Create();
 }

然后,您创建一个类来表示仅再次使用容器来解析实例的工厂:

 public class DownloaderFactory : IDownloaderFactory
 {
     private UnityContainer _Container;
     public DownloaderFactory(UnityContainer container)
     {
         this._Container = container;
     }

     public IDownloader Create()
     {
         return this._Container.Resolve<IDownloader>();
     }
 }

使用这种方法更加明确,并且可以更好地处理容器,同时它仍然使容器远离您的应用程序和业务逻辑,现在您只需要对SearchViewModel类进行一些小调整:

class SearchViewModel
{
   private readonly IDownloaderFactory _downloaderFactory;
   private readonly INewObject _newObject;

   public SearchViewModel(IDownloaderFactory downloaderFactory, INewObject newObject)
   {
       _downloaderFactory = downloaderFactory;
       _newObject = newObject;

       Console.WriteLine(downloaderFactory.Create().GetHashCode());
       Console.WriteLine(downloaderFactory.Create().GetHashCode());
   }

}

现在你可以看到它正常工作并且每次都创建新的实例。

设置容器如下所示:

        var container = new UnityContainer();
        container.RegisterType<IDownloader, Downloader>();
        container.RegisterType<INewObject, NewObject>();
        container.RegisterType<IDownloaderFactory, DownloaderFactory>();
        container.RegisterType<SearchViewModel>();
        container.RegisterInstance(container);
        var model = container.Resolve<SearchViewModel>();

请注意,您需要注册正在使用的容器的实例,以便工厂使用此方法或ThreadLocal实例或其他内容获取相同的实例。

注意: 另外,请注意使用Func方法或使用容器来解析下载程序可能会导致客户端产生不良影响。例如,如果容器默认设置为对Downloader的对象是瞬态的,则每次都会创建一个新实例。在容器上查看生命周期可能导致客户端每次都获得相同的实例。在这种情况下,最好在工厂中手动构造下载器对象,并仅将容器用于下载器的参数。