I have the following code:
_container = new UnityContainer();
_container.RegisterType<IDownloader, Downloader>();
_container.RegisterType<INewObject, NewObject>();
_container.RegisterType<SearchViewModel>();
SearchViewModel
class with constructor injection:
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;
}
}
The question: How to register SearchViewModel
that has Fun<>
as parameter?
_container.RegisterType<SearchViewModel>(new InjectionConstructor(DownloaderFactory()));
The code above works only without INewObject
.
The goal: Resolve factory with InjectionConstructor
and resolve INewObject, INewObject2, INewObject3
automatically (like without parameters: RegisterType<SearchViewModel>()
).
Is it possible? Maybe alternates?
I have solved the problem:
_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i =>
new Func<IDownloader> (() => _container.Resolve<IDownloader>())));
_container.RegisterType<SearchViewModel>();
new Func is a key, because before I tried:
_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i =>
_container.Resolve<IDownloader>()));
Also the better way to use IDownloaderFactory
instead of Func<IDownloader> downloaderFactory
. IDownloaderFactory
can encapsulate the delegate.
Also I think that using a delegate as dependency inside factory is better solution than broken Composition Root.
The generally accepted pattern to use here is to declare an abstract factory and make it slightly more explicit:
public interface IDownloaderFactory
{
IDownloader Create();
}
Then you create a class to represent the factory that simply uses the container again to resolve instances:
public class DownloaderFactory : IDownloaderFactory
{
private UnityContainer _Container;
public DownloaderFactory(UnityContainer container)
{
this._Container = container;
}
public IDownloader Create()
{
return this._Container.Resolve<IDownloader>();
}
}
Using this approach is more explicit and plays more nicely with the containers, also it still keeps the container away from your application and business logic, now you just need a small adjustment to your SearchViewModel class:
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());
}
}
Now you can see it just works and creates new instances each time.
Setting up the container would look like this:
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>();
Notice that you need to register the instance of the container you are working with so that the factory gets the same instance either using this method or a ThreadLocal instancing or something.
Note: also just be wary of the fact that using the Func approach or using the container to resolve the downloader may cause undesired effects in your client. For instance if the container is set up by default to be transient to objects of Downloader then a new instance is created each time. Chaning the lifetime on the container may result in the client to get the same instance each time. In such a case it is better to manually construct the downloader object in the factory and use the container only for the arguments of downloader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With