Register null as instance in Unity container

南笙酒味 提交于 2019-11-27 23:15:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!