Зарегистрировать null как экземпляр в контейнере Unity
У меня есть класс репозитория с дополнительной зависимостью:
class MyRepository : BaseRepository, IMyRepository
{
public MyRepository(IDataContext dataContext, ICacheProvider cacheProvider = null)
: base(dataContext, cacheProvider)
{}
// …
}
Существование параметра cacheProvider выступает в качестве стратегии для репозитория.
Я хочу установить контейнер Unity следующим образом:
Container.RegisterType<IDataContext, MyDataContext>(new PerResolveLifetimeManager(), new InjectionConstructor())
.RegisterInstance<ICacheProvider>(null) // ???
.RegisterType<IMyRepository, MyRepository>();
т.е. не указывая конкретного InjectionConstructor с одним параметром для MyRepository, но используйте конструктор по умолчанию с нулевым параметром cacheProvider.
Есть ли способ сделать это?
Ответы
Ответ 1
В вызове .RegisterType<IMyRepository, MyRepository>()
укажите InjectionConstructor с OptionalParameter, как в
.RegisterType<IMyRepository, MyRepository>(new InjectionConstructor(
new ResolvedParameter<IDataContext>(),
new OptionalParameter<ICacheProvider>()));
Ответ 2
Я обнаружил, что RegisterType вместо экземпляра Register поддерживает возврат null.
container.RegisterType<IInterface>(new InjectionFactory((c) => null));
Это был самый простой способ получения фактического null
для возврата.
Ответ 3
Для "приятных" зависимостей вы должны использовать инъекцию свойств вместо инъекции ctor. Конфигурация будет выглядеть примерно так:
public class MyRepository
{
public ICacheProvider Cache { get; set; }
}
container.RegisterType<MyRepository>(new InjectionProperty("Cache", typeof(ICacheProvider)));
Это введет реализацию ICacheProvider
в свойство с именем Cache
вашего MyRepository
. Поскольку вам нужно будет выполнять нулевые проверки, когда вы делаете вызов свойства Cache
внутри вашего класса репозитория, я бы пошел с предложением @dtryon и реализовал NullCacheProvider
. Это намного удобнее и менее подвержено ошибкам.
Ответ 4
Самое простое, не устаревшее решение
Вызов RegisterType с InjectionFactory в настоящее время устарел, поэтому вот рекомендуемый в настоящее время подход:
container.RegisterFactory<ITypeToResolve>(c => null);
Гибкий метод расширения
Или, если вы хотите создать метод расширения для возврата всего, что вы хотите, вы можете сделать что-то вроде:
public static void RegisterFactory<TToResolve>(IUnityContainer container, Func<TToResolve> factory) =>
container.RegisterFactory<TToResolve>(c => factory.Invoke());
Затем потреблять то, что вы будете делать:
container.RegisterFactory<ITypeToResolve>(() => new MyTypeToResolve());
Ответ 5
Я закончил с реализации своего рода шаблона NullObject для моей дополнительной зависимости:
public class NullCacheProvider : ICacheProvider
{
// …
}
И в базовом классе репозитория я проверяю:
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);
}
}
Тогда в проектах, где мне не нужен кеш, я настроил Unity следующим образом:
container
.RegisterType<IDataContext, MyDataContext>(new PerResolveLifetimeManager(), new InjectionConstructor())
.RegisterType<ICacheProvider, NullCacheProvider>()
.RegisterType<IMyRepository, MyRepository>();
Дело в том, что конкретный репозиторий может действовать по-разному в зависимости от факта существования дополнительной зависимости. Это может показаться некоторым архитектурным недостатком, но решение отвечает моим требованиям.