2012-03-22 17 views
5

我有以下代碼:如何註冊一個具有`Func <>`作爲參數的類?

_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; 
    }   
} 

問題:如何註冊SearchViewModelFun<>作爲參數?

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

上面的代碼只工作不INewObject

目標:解決工廠InjectionConstructor並自動解決INewObject, INewObject2, INewObject3(如不帶參數:RegisterType<SearchViewModel>())。

可能嗎?也許替代?

+1

爲什麼你不使用Setter注入INewObject參數? – daryal 2012-03-22 12:46:05

+0

爲什麼要讓SearchViewModel取決於Func ?這不是抽象的抽象嗎?我認爲你應該直接注入IDownloader接口。 IDownloader的具體實現可以封裝工廠行爲。在此處查看代碼示例:http://stackoverflow.com/questions/9757953/can-any-of-existing-ioc-containers-create-the-lazy-proxy-classes-dynamically – 2012-03-22 15:30:45

回答

8

我已經解決了這個問題:

_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> downloaderFactoryIDownloaderFactory可以封裝委託。

此外,我認爲使用委託作爲工廠內的依賴關係比破碎的組合根更好的解決方案。

2

普遍接受的模式用在這裏是爲了宣佈一個抽象工廠並使其略微更加明確:

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對象的臨時變量,那麼每次都會創建一個新實例。改變容器的生命週期可能會導致客戶端每次都獲得相同的實例。在這種情況下,最好在工廠中手動構建下載器對象,並僅將容器用於下載器的參數。

相關問題