2012-04-04 2 views
1

Я пытаюсь сделать следующее с Autofac:Autofac: разрешить общий интерфейс с дополнительными параметрами, с помощью заводских делегатов

У меня есть класс UnitOfWork:

public class UnitOfWork : IUnitOfWork 
    { 
    IContext contextA { get; set ;} 
    IContext contextB { get; set ;} 

    public UnitOfWork(IContext contextA, IContext contextB) 
    { 
    this.contextA = contextA; 
    this.contextB = contextB; 
    } 

    public void Save() 
    { 
    this.contextA.Save(); 
    this.contextB.Save(); 
    } 

    ... 
    } 

У меня также есть общий класс GenericRepo :

public class GenericRepo<T> : IRepo<T> 
    { 
    private IContext context; 

    public GenericRepo(IContext context) 
    { 
    this.context = context; 
    } 
    } 

Не вводить интерфейсы, но они есть.

Тогда у меня есть эти делегаты:

public delegate IUnitOfWork IUnitOfWorkFactory(); 

public delegate IRepo<T> IRepoFactory<T>(IUnitOfWork unitOfWork = null); 

Теперь проблема заключается в следующем:

Мне нужно, чтобы иметь возможность создавать репозитории. В зависимости от типа общего репозитория он должен использовать другой контекст. Я не хочу, чтобы вызывающий код должен был знать, в каком контексте используется репо, поэтому я не могу использовать контекст в качестве параметра, он должен быть UnitOfWork.

Но поскольку общий репо является общим, он не знает, какой контекст должен получить от UnitOfWork, поэтому он должен получить контекст через свой конструктор, а не UnitOfWork.

Кроме того, иногда код вызова не заботится об UnitOfWork (потому что его не нужно сохранять), и в этом случае UnitOfWork должен быть создан на лету - ему все еще нужно, чтобы его данные из.

Так мне это нужно для работы:

public void TestCode(IRepoFactory<TypeA> repoFacA, IRepoFactory<TypeB> repoFacB, IUnitOfWorkFactory uowFactory) 
    { 
    IRepo<TypeA> repoA = repoFacA(); //repoA has contextA from a new UnitOfWork 
    IRepo<TypeB> repoB = repoFacB(); //repoB has contextB from a new (different) UnitOfWork 

    IUnitOfWork uow = uowFactory(); 
    IRepo<TypeA> repoA_2 = repoFacA(uow); //repoA_2 has contextA from uow 
    IRepo<TypeB> repoB_2 = repoFacB(uow); //repoB_2 has contextB from uow 
    } 

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

Он также должен работать без параметра, и в этом случае Autofac должен решить и использовать сам параметр.

Любые идеи о том, как зарегистрировать все это в AutoFac?

+0

Рассматривали ли вы с помощью клавиш HTTP: // липкая.gl/aT80h или метаданные http://goo.gl/1RU06? – cecilphillip

ответ

2

Хорошо, нашел это сам.

Это, как я зарегистрируйте делегатов:

 builder.Register((b, p) => new GenericRepo<TypeA>(((((p.First() as ConstantParameter)).Value as UnitOfWork) ?? b.Resolve<IUnitOfWork>()).ContextA)).As<IRepo<TypeA>>(); 
     builder.Register((b, p) => new GenericRepo<TypeB>(((((p.First() as ConstantParameter)).Value as UnitOfWork) ?? b.Resolve<IUnitOfWork>()).ContextB)).As<IRepo<TypeB>>(); 

Edit:

Или лучше сделать это в общем виде для первой:

builder.RegisterGeneric(typeof(GenericRepository<,>)).WithParameter((pi, icc) => true, (pi, icc) => (((((icc as IInstanceLookup).Parameters.First()) as ConstantParameter).Value as IUnitOfWork) ?? icc.Resolve<IUnitOfWork>()).ContextA).As(typeof(IEntityRepository<,>)); 

Первый параметр «WithParameter()» должен быть там, и он должен возвращать true. Я думаю, если бы я хотел отфильтровать, какие параметры были даны, я должен был бы сделать это там.

В любом случае. Это позволяет, если у вас есть много типов, которым нужен ContextA, и только некоторые из них, которые нуждаются в contextB, чтобы сделать общую регистрацию для A, а затем добавить исключения для B впоследствии.

Предложения о том, как сделать это более чистый или устают глаза всегда приветствуются :-)

Смежные вопросы