StructureMap 2.6.1, IRepository и EFRepository

#generics #structuremap

#дженерики #structuremap

Вопрос:

Итак, я подумал, что буду хитрым и попробую это. Мне нужно передавать контекст, не обновляя его каждый раз, И иметь возможность определять сопоставления (Entity framework) — для этого мне нужно наследовать, а затем переопределить класс DbContext. Я хотел бы сохранить его подключаемым к любому контексту, который я добавляю, так что это то, что привело меня к этому. Я получил интерфейс IRepository, который принимает (объект) с вашими обычными подозреваемыми в нем, и его реализацию с зависимостью от IContextFactory …

 public interface IContextFactory<T> where T : DbContext
{
    T Context { get; }
}
  

И в моем «EFRepository»

 public class EFRepository<T, TContext> : IRepository<T> where T : class
        where TContext : DbContext
{

    public EFRepository(IContextFactory<TContext> contextFactory)
    {
    }
}
  

В моем отображении я выполнил одно из этих заданий…

         x.For(typeof(IContextFactory<>)).Use(typeof(ContextFactory<>));
        x.For(typeof(IRepository<>)).Use(typeof(EFRepository<,>));
  

Хорошо, круто. В своих модульных тестах я пробую это таким образом…

         var repository = ObjectFactory.GetInstance<EFRepository<Currency, EFContext>>();
        var repository2 = ObjectFactory.GetInstance<IRepository<Currency>>();
  

Первый работает, проблем нет. 2-й, я получаю удар с

Количество предоставленных универсальных аргументов не равно арности определения универсального типа. Имя параметра: создание экземпляра

Я предполагаю, что это потому, что я не указываю structuremap, какой дженерик передать в IRepository, поскольку я передаю 2? Как мне это сделать? …могу ли я это сделать?

Ответ №1:

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

Сначала вам нужно изменить способ создания EFRepository<,> . Используя .Use(context => ...) перегрузку, вы можете получить доступ к контексту, подобному context.BuildStack.Current.RequestedType.GetGenericArguments() , чтобы получить универсальный тип, к которому вы хотите получить доступ. Затем вы можете создать новый экземпляр, EFRepository<,> используя отражение и получая IContextFactory из контекста.

Таким образом, независимо от того, что что-то вроде

             ObjectFactory.Configure(x =>
            {
                x.For(typeof(IContextFactory<>)).Use(typeof(ContextFactory<>));
                x.For(typeof (IRepository<>)).Use(context =>
                    {
                        Type arg1 = context.BuildStack.Current.RequestedType.
                            GetGenericArguments()[0];

                        Type targetType =
                            typeof (EfRepository<,>).MakeGenericType(new[] {arg1, typeof (IContextFactory<>)});

                        return Activator.CreateInstance(targetType,
                                                        new[] {context.GetInstance(typeof (IContextFactory<>))});

                    });
                //x.For(typeof(IRepository<>)).Use(typeof(EfRepository<,>));
            });

        var repository = ObjectFactory.GetInstance<EfRepository<Currency, EfContext>>();
        var repository2 = ObjectFactory.GetInstance<IRepository<Currency>>();
  

Поможет вам пройти большую часть пути к этому. Я думаю, вам все еще нужно правильно установить generic для второго универсального параметра TargetType, прежде чем он заработает.

Комментарии:

1. итак, реальный ответ таков: «это отстой, делай это другим способом» … Я согласен с этим! Я пока оставлю вопрос открытым, но это может быть правильным ответом. И вы правы, это действительно отстой. 🙁