Разрешение списка классов, которые реализуют универсальный интерфейс и абстрактный класс с Autofac - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь разрешить стратегию, используя фабрику.Эта фабрика генерирует открытый общий интерфейс.Это зависит от IEnumerable этого универсального интерфейса.Я могу получить IEnumerable не универсального для работы, но с универсальными я получаю пустой список.

Я также могу разрешить класс напрямую, но не список.

Дополнительным предостережением является то, что у нас могут быть потенциально неограниченные репозитории, поэтому регистрация их по отдельности будет болезненной.

Я пробовал эти способы регистрации в Autofac

var dataAccess = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(dataAccess).AsClosedTypesOf(typeof(Repositories.IRepository<>));

builder.RegisterAssemblyTypes(dataAccess)
                       .Where(t => IsAssignableToGenericType(t, typeof(Repositories.IRepository<>)) && !t.IsAbstract && !t.IsInterface)
                       .AsImplementedInterfaces();

builder.RegisterAssemblyTypes(dataAccess)
                         .Where(t => IsAssignableToGenericType(t, typeof(Repositories.IRepository<>)) && !t.IsAbstract && !t.IsInterface);

public interface IRepository<T> where T : BaseProcessorType
{
    Task Add(T data);
}

public abstract class BaseRepository<T> : IRepository<T> where T : BaseProcessorType
{
    public async Task Add(T data)
    {
        // something
    }
}


public class ActivityRepository : BaseRepository<Activity>, IRepository<Activity>
{
    public ActivityRepository() : base()
    {
    }

    public override async Task Add(Activity data)
    {
        // override
    }
}

Тогда я хотел бы разрешить

var lol = something.Resolve<IEnumerable<Repositories.IRepository<BaseProcessorType>>>();

Но, к сожалению, это возвращает пустой список IRepositories.

1 Ответ

0 голосов
/ 15 февраля 2019

Давайте забудем о Autofac и попробуем получить коллекцию с чистым C #

IEnumerable<IRepository<BaseProcessorType>> l = new IRepository<BaseProcessorType>[] {
                                                       new ActivityRepository() 
                                                };

с примером кода, в котором компилятор выдаст ошибку

ОшибкаCS0266 - невозможно неявное преобразование типа ActivityRepository в IRepository<BaseProcessorType>.Существует явное преобразование (вам не хватает приведения?)

Основная ошибка заключается в том, что ActivityRepository не конвертируется в IRepository<BaseProcessorType>.Чтобы разрешить это приведение, вы должны сделать аргумент T ковариантным, используя ключевое слово out

public interface IRepository<out T> where T : BaseProcessorType 
{}

Но при этом у вас не будет метода с параметром T

Ошибка CS1961 Недопустимая дисперсия: параметр типа T должен быть контравариантно действительным для IRepository<T>.Add(T).T является ковариантным.

Чтобы понять, почему это запрещено, давайте посмотрим этот пример кода:

IRepository<BaseProcessorType> r = new Activity1Repository();
r.Add(new Activity2());

В этом примере кода r работает с Activity1, но вы хотите добавить Activity2 и Activity1 не Activity2.

Одним из решений было бы не использовать T в качестве параметра типа, а использовать BaseProcessorType

public interface IRepository<out T> where T : BaseProcessorType
{
    Task Add(BaseProcessorType data);
}

Таким образом, чистое решение на C # является действительным.

InДля разрешения IEnumerable<IRepository<BaseProcessorType>> вам необходимо зарегистрировать ваши типы как IRepository<BaseProcessorType>.

builder.RegisterAssemblyTypes(dataAccess)
       .As(typeof(IRepository<BaseProcessorType>));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...