问题
I have a repository class with optional dependency:
class MyRepository : BaseRepository, IMyRepository
{
public MyRepository(IDataContext dataContext, ICacheProvider cacheProvider = null)
: base(dataContext, cacheProvider)
{}
// …
}
The existence of cacheProvider parameter acts as strategy for the repository. I want setup Unity container like this:
Container.RegisterType<IDataContext, MyDataContext>(new PerResolveLifetimeManager(), new InjectionConstructor())
.RegisterInstance<ICacheProvider>(null) // ???
.RegisterType<IMyRepository, MyRepository>();
I.e. not pointing out particular InjectionConstructor with one parameter for MyRepository, but use default constructor with null as cacheProvider parameter.
Is there any way to do this?
回答1:
In the .RegisterType<IMyRepository, MyRepository>() call, specify the InjectionConstructor with an OptionalParameter, as in
.RegisterType<IMyRepository, MyRepository>(new InjectionConstructor(
new ResolvedParameter<IDataContext>(),
new OptionalParameter<ICacheProvider>()));
回答2:
I found that RegisterType, instead of Register instance, supports returning null.
container.RegisterType<IInterface>(new InjectionFactory((c) => null));
This was the most straightforward way of getting an actual null to be returned.
回答3:
For 'nice to have' dependencies you should use property injection instead of ctor injection. Config would look something like this:
public class MyRepository
{
public ICacheProvider Cache { get; set; }
}
container.RegisterType<MyRepository>(new InjectionProperty("Cache", typeof(ICacheProvider)));
That would inject an implementation of ICacheProvider into a property named Cache of your MyRepository. As you would have to implement null checks wherever you make a call to the Cache property inside your repository class I would go with @dtryon's proposal and implement a NullCacheProvider. That is far more convenient and less error prone.
回答4:
Simplest Non-Obsolete solution
Calling RegisterType with an InjectionFactory is currently obsolete, so here is the currently recommended approach:
container.RegisterFactory<ITypeToResolve>(c => null);
Flexible Extension Method
Or if you want to make an extension method to return anything you want you could do something like:
public static void RegisterFactory<TToResolve>(IUnityContainer container, Func<TToResolve> factory) =>
container.RegisterFactory<TToResolve>(c => factory.Invoke());
Then to consume that you'd do:
container.RegisterFactory<ITypeToResolve>(() => new MyTypeToResolve());
回答5:
I've ended with implementing some sort of a NullObject pattern on my optional dependency:
public class NullCacheProvider : ICacheProvider
{
// …
}
And in the base repository class i have check:
public class BaseRepository
{
protected readonly ICacheProvider CacheProvider;
protected readonly bool ShouldUseCache;
protected BaseRepository(IDataContext context, ICacheProvider cacheProvider)
{
CacheProvider = cacheProvider;
ShouldUseCache =
CacheProvider != null && !(CacheProvider is NullCacheProvider);
}
}
Then in a projects where i don't need a cache i have configured Unity like this:
container
.RegisterType<IDataContext, MyDataContext>(new PerResolveLifetimeManager(), new InjectionConstructor())
.RegisterType<ICacheProvider, NullCacheProvider>()
.RegisterType<IMyRepository, MyRepository>();
The point of all this is that the particular repository may act differently depending on fact of existence the optional dependency. It may seem as some architectural flaw but the solution meets my requirements.
来源:https://stackoverflow.com/questions/11392670/register-null-as-instance-in-unity-container