2015-11-24 5 views
0

Я использую CacheManager и использует фабрику для создания экземпляров. Я не хочу регистрировать каждый тип ICacheManager, который я объявляю, поэтому я ищу способ зарегистрировать общий тип с помощью метода динамической разрешимости. Используя Ninject, я мог бы сделать это:Регистрация Autofac разрешена методом

kernel 
    .Bind(typeof(ICacheManager<>)) 
    .ToMethod((context) => CacheFactory.FromConfiguration(context.GenericArguments[0], "defaultCache")) 
    .InSingletonScope(); 

где context.GenericArguments [0] будет тип моей родовой. Например, объект от

ICacheManager<object> cache; 

Как мне сделать что-то подобное с помощью Autofac?

Редактировать

Рабочая IRegistrationSource на основе ответа Кирилловской ниже. SingleInstance требуется, поскольку CacheManager добавляет ключи с идентификатором экземпляра CacheManager.

public class CacheManagerRegistrationSource : IRegistrationSource 
{ 
    public Boolean IsAdapterForIndividualComponents 
    { 
     get 
     { 
      return false; 
     } 
    } 

    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) 
    { 
     IServiceWithType typedService = service as IServiceWithType; 
     if (typedService == null || !typedService.ServiceType.IsGenericType) 
     { 
      yield break; 
     } 

     Type cacheManagerType = typedService.ServiceType; 
     if (cacheManagerType.GetGenericTypeDefinition() != typeof(ICacheManager<>)) 
     { 
      yield break; 
     } 

     IComponentRegistration registration = (IComponentRegistration)RegistrationBuilder.ForDelegate(cacheManagerType, (c, p) => 
     { 
      return CacheFactory.FromConfiguration(cacheManagerType.GetGenericArguments()[0], "defaultCache"); 
     }) 
     .SingleInstance() 
     .CreateRegistration(); 

     yield return registration; 
    } 
} 

ответ

1

По умолчанию Autofac не позволяет получить общий тип объекта регистрации. Там не существует простой встроенный способ сделать это, но вы можете использовать IRegistrationSource, чтобы достичь того, чего вы хотите:

public class CacheManagerRegistrationSource : IRegistrationSource 
{ 
    public Boolean IsAdapterForIndividualComponents 
    { 
     get 
     { 
      return false; 
     } 
    } 

    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) 
    { 
     IServiceWithType typedService = service as IServiceWithType; 
     if (typedService == null) 
     { 
      yield break; 
     } 

     Type cacheManagerType = typedService.ServiceType 
              .GetInterfaces() 
              .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICacheManager<>)) 
              .FirstOrDefault(); 

     if (cacheManagerType == null) 
     { 
      yield break; 
     } 

     IComponentRegistration registration = 
      RegistrationBuilder.ForDelegate(cacheManagerType, (c, p) => { 
       return CacheFactory.FromConfiguration(cacheManagerType.GetGenericArguments()[0], "defaultCache"); 
      }) 
      .SingleInstance() 
      .CreateRegistration(); 

     yield return registration; 
    } 
} 

, то вам придется зарегистрировать источник регистрации, выполнив:

builder.RegisterSource(new CacheManagerRegistrationSource()); 

Этот это способ, которым работает метод RegisterGeneric.

+0

Спасибо. Твой ответ был почти точным. Я опубликовал рабочий код в моем вопросе. –

0

Это ужасно, но вы можете сделать следующее:

var builder = new ContainerBuilder(); 
builder.RegisterGeneric(typeof(ICacheManager<>)) 
    .OnActivating(e => 
    { 
     var instance = typeof(CacheFactory).GetMethod("FromConfiguration").MakeGenericMethod 
      e.Instance.GetType().GenericTypeArguments[0]) 
      .Invoke(null, new object[] { "..." }); 
     e.ReplaceInstance(instance); 
    }); 
+0

Когда я пытаюсь что я получаю сообщение об ошибке: исключение типа «System.InvalidOperationException» произошла в Autofac.dll, но не был обработан в пользовательском коде Дополнительной информации: Тип «CacheManager.Core.ICacheManager'1» не реализует интерфейс 'CacheManager.Core.ICacheManager'1'. –

+0

О, я понимаю, почему. Я случайно протестировал этот код со следующим объявлением mock 'public class ICacheManager {}'. Обратите внимание: это не интерфейс, а класс. – Tamas

+0

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

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