Подтвердить что ты не робот

Зарегистрировать 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.

Есть ли способ сделать это?

4b9b3361

Ответ 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>();

Дело в том, что конкретный репозиторий может действовать по-разному в зависимости от факта существования дополнительной зависимости. Это может показаться некоторым архитектурным недостатком, но решение отвечает моим требованиям.