我有以下代码:
_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>()
)。
有可能吗?也许是替补?
答案 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的对象是瞬态的,则每次都会创建一个新实例。在容器上查看生命周期可能导致客户端每次都获得相同的实例。在这种情况下,最好在工厂中手动构造下载器对象,并仅将容器用于下载器的参数。