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

Автоматически разрешать интерфейс <T> для реализации <T> в StructureMap (отличаются только общим типом T)

У меня есть интерфейс (IRepository<T>), который в настоящее время расширяется для каждого конкретного репозитория, то есть: IUserRepository : IRepository<User>.

Каждый из этих интерфейсов имеет соответствующие конкретные классы, то есть: UserRepository : Repository<User>, IUserRepository.

Эти отдельные репозитории не добавляют каких-либо дополнительных функций, это все пустые интерфейсы/классы, которые используются просто для передачи генериков.

Я использую StructureMap для решения IUserRepository в UserRepository, используя реестр со сборочным сканером и некоторыми соглашениями об именах.

Мне бы хотелось, чтобы это переместилось в более оптимизированное состояние, где вместо того, чтобы обходить экземпляры IUserRepository и разрешать его до UserRepository, я могу обойти IRepository<User> и разрешить его Repository<User>.

Это устранит необходимость создания этих дополнительных пустых интерфейсов и классов.

Я не могу разработать способ конфигурации StructureMap для настройки этого общего сопоставления. Что-то вроде этого:

For(typeof(IRepository<>).Use(typeof(Repository<>)).WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter();

Edit

После получения первой пары ответов я хочу уточнить это немного.

Я не хочу создавать отдельные классы для бита For конфигурации. Я хочу иметь следующие классы/интерфейсы в моем коде:

  • IRepository<T> where T : Entity
  • Repository<T> : IRepository<T> where T : Entity
  • Person : Entity
  • Product : Entity
  • Order : Entity
  • Whatever : Entity

И получим следующие сопоставления с соглашением:

IRepository<Person> => Repository<Person>
IRepository<Product> => Repository<Product>
IRepository<Order> => Repository<Order>
IRepository<Whatever> => Repository<Whatever>

Но я не хочу создавать сопоставление для каждого из них, ala:

For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();

Я хочу одно сопоставление, которое будет работать для любого IRepository:

For<IRepository<>>().Use<Repository<>>().WithTheSameGenericType();

Затем я использовал бы это, чтобы внедрить репозитории в службы:

public MyService(IRepository<User> userRepository)

И ожидаем, что это будет разрешено для Repository<User> во время выполнения.

4b9b3361

Ответ 1

Оказывается, нет никакого причудливого метода для вызова или нет подходящей проводки, вы просто используете For и Use (не общие версии):

public class DataRegistry : Registry
{
    public DataRegistry()
    {
        For(typeof (IRepository<>)).Use(typeof(Repository<>));
    }
}

Когда я вставляю a IRepository<Person>, он решается теперь как Repository<Person>.

Я столкнулся с ошибкой 104, говоря, что Repository не был подключен для IRepository. Это было потому, что хранилище было отмечено abstract. При этом он не является абстрактным, фиксирует эту ошибку и работает по желанию.

Ответ 2

Я предлагаю вам взглянуть на метод AddAllTypesOf. У меня был какой-то аналогичный код и я достиг своих целей, используя его (и сохранял функцию автоматического регистрации).

В вашем случае вы должны просто изменить

For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();

к

AddAllTypesOf(typeof(IRepository<>));

В конце концов, ваш контейнер будет похож на:

return new Container(x =>
        {
            x.Scan(y =>
            {
                y.TheCallingAssembly();
                y.AddAllTypesOf(typeof(IRepository<>));
                y.WithDefaultConventions();
            });
        });

Ответ 3

Вот пример. Структурная карта позволит вам сделать и то и другое.

 //IRepository
 For<IMemberRepository>().Add<MemberRepository>();

 //IRepository<T>
 For<IRepository<Member>>().Add<MemberRepository>();

Тогда полезно спросить типы, просто зная общий тип во время выполнения:

Type repositoryType = typeof(IRepository<>).MakeGenericType(modelType);
IocResolve.Resolve(repositoryType);

Ответ 5

Посмотрите интерфейс IRegistrationConvention.

public class DomainRegistry : Registry
{
    public DomainRegistry()
        : base()
    {
        Scan(y =>
        {
            y.AssemblyContainingType<IRepository>();
            y.Assembly(Assembly.GetExecutingAssembly().FullName);
            y.With(new RepositoryTypeScanner());
        });

Где RepositoryTypeScanner:

public class RepositoryTypeScanner : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
      ...