У нас есть интерфейс для работы с DAL с довольно простым определением:
interface IRepository<T> : IQueriable<T> // so we can read data from database
{
Save(T document); // dozen of methods here
}
В основном мы используем две реализации: реальную версию и версию памяти для модульного тестирования.Вот объявления одного из классов:
public RealRepository : IRepository<AccountEntity> { ... }
// typical IOC usage
services.AddSingleton<IRepository<AccountEntity>, RealRepository<AccountEntity>>();
Теперь мы работаем над выделением основной базы кода для пользовательской версии проекта, и нам нужны настраиваемые поля в данных и иногда настраиваемое поведение в репозитории.Большинство классов подходят для базовой реализации, но для других потребуется конкретная реализация.Поэтому моя цель состоит в том, чтобы получить следующие сервисы в:
var repository = new RealRepository<CustomAccountEntity>();
services.AddSingleton(IRepository<AccountEntity>, repository);
// for new classes
services.AddSingleton(IRepository<CustomAccountEntity>, repository);
Я пытался добавить out T
в IRepository, но я использую T во входных параметрах, и это дало ошибку времени компиляции "Invalid Variance".
Я вижу решение, добавив параметр второго типа в интерфейс, чтобы он выглядел следующим образом:
IRepository<TBase, out TChild> : IQueriable<TChild> {
Save (T document);
}
Наконец, Вопрос: Как сделать изменение на 100% обратно совместимым?
Что я пробовал:
- Добавить
IRepository<T>: IRepository<T,T>
-> соответствует, но RealRepository
больше не реализует IRepository
. - Добавить 2 интерфейса в реализацию:
public class RealRepository<TBase, TChild>: IRepository<TBase, TChild>, IRepository<TChild>
но это дает ошибку комплимента 'не может реализовать оба ... и ..., потому что они могут объединиться для некоторых замен параметров типа'