2013-10-15 2 views
3

Я хочу создать Autofac Module, который переопределяет тип целевого объекта регистрации на основе определенных критериев. Однако новый тип будет иметь один и тот же конструктор и должен быть создан с использованием тех же переопределений параметров, что и исходный тип.Autofac: переопределение типа целевого объекта регистрации из модуля

Я могу использовать AttachToComponentRegistration, чтобы решить, должна ли регистрация быть переопределена, но само переопределение создает проблему. Я предполагаю, что мне нужно заменить IInstanceActivator (в частности,), но я не вижу способа получить полную информацию о существующих ReflectionActivator. Кажется, нет никакого свойства для получения настроенных параметров.

Пример (упрощенный код):

protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) { 
    base.AttachToComponentRegistration(componentRegistry, registration); 
    var reflectionActivator = ((ComponentRegistration)registration).Activator as ReflectionActivator; 
    if (reflectionActivator == null) 
     return; 

    var replacementType = ReplaceType(reflectionActivator.LimitType); 
    if (replacementType == reflectionActivator.LimitType) 
     return; 

    ((ComponentRegistration)registration).Activator = new ReflectionActivator(
     replacementType, 
     reflectionActivator.ConstructorFinder, 
     reflectionActivator.ConstructorSelector, 
     configuredParameters: ???, // how to get this? 
     configuredProperties: ??? // or this? 
    ); 
} 

Является ли это что-то, что можно сделать проще и я просто отсутствует что-то здесь?

+0

Почему вы не просто переопределить регистрацию в вашем Modele? Итак, 'builder.Register .As ', потому что, если вы не предоставляете модификатор '.PreserveExistingDefaults()', Autofac просто переопределит предыдущую регистрацию. – nemesv

+0

@nemesv Я, вероятно, немного неясен - то, что я хочу сделать, это заменить определенные типы целей другим (динамически сгенерированным) типом, который имеет тот же самый конструктор. В вашем подходе я должен либо заранее знать все типы заранее (я не знаю), либо найти способ регистрации параметров для восстановления регистрации (которая возвращается к моему первоначальному вопросу). –

+0

@ AndreySchchekin. Трудно получить то, что вы хотите сделать, можете ли вы отправить пример кода, пожалуйста. –

ответ

1

ReflectionActivator содержит сконфигурированные параметры и настраиваемые свойства в своих частных полях. Вы можете читать их с помощью Reflection

var configuredParameters = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredParameters", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator); 

var configuredProperties = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredProperties", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator); 

И рабочий пример:

class Program 
{ 
    interface IInterface 
    { 
    } 

    class MyClass : IInterface 
    { 
     private readonly string _name; 

     public MyClass(string name) 
     { 
      _name = name; 
     } 

     protected MyClass() 
     { 
     } 

     public override string ToString() 
     { 
      return string.Format("{0} {1}", GetType(), _name); 
     } 
    } 

    class MyReplacementClass : MyClass 
    { 
     private readonly string _name; 

     public MyReplacementClass(string name) 
     { 
      _name = name; 
     } 

     public override string ToString() 
     { 
      return string.Format("{0} {1}", GetType(), _name); 
     } 
    } 

    class MyModule : Module 
    { 
     protected override void Load(ContainerBuilder builder) 
     { 
      builder.RegisterType<MyClass>().As<IInterface>().WithParameter("name", "Parameter"); 
     } 

     protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, 
      IComponentRegistration registration) 
     { 
      var reflectionActivator = ((ComponentRegistration) registration).Activator as ReflectionActivator; 
      if (reflectionActivator == null) 
       return; 

      var replacementType = ReplaceType(reflectionActivator.LimitType); 
      if (replacementType == reflectionActivator.LimitType) 
       return; 

      var configuredParameters = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredParameters", 
       BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator); 

      var configuredProperties = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredProperties", 
       BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator); 

      ((ComponentRegistration) registration).Activator = new ReflectionActivator(
       replacementType, 
       reflectionActivator.ConstructorFinder, 
       reflectionActivator.ConstructorSelector, 
       configuredParameters, 
       configuredProperties 
       ); 
     } 

     private Type ReplaceType(Type limitType) 
     { 
      return typeof (MyReplacementClass); 
     } 
    } 

    static void Main(string[] args) 
    { 
     var builer = new ContainerBuilder(); 
     builer.RegisterModule<MyModule>(); 

     using (var container = builer.Build()) 
     { 
      var myClass = container.Resolve<IInterface>(); 
      Console.WriteLine(myClass); 
      Console.ReadKey(); 
     } 
    } 
} 
+0

Спасибо. К сожалению, мне придется отправить вопрос Autofac, если я продолжу работу с побочным проектом, который требует этого. Но это правильный ответ. –

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