2013-10-15 42 views
3

我想創建一個Autofac Module,它根據特定條件覆蓋註冊目標類型。然而,新類型將具有相同的構造函數,並且應該使用與原始類型相同的參數覆蓋來創建。Autofac:從模塊重寫註冊目標類型

我可以使用AttachToComponentRegistration來決定是否應該重寫註冊,但重寫本身會帶來問題。我想我需要更換IInstanceActivator(特別是ReflectionActivator),但我沒有看到獲取有關現有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

@AndreyShchekin你很難得到你想要做的事情,你可以發佈示例代碼嗎? –

回答

1

ReflectionActivator在其專用字段中包含configuredParameters和configuredProperties。您可以通過反射

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提交問題。但這是一個有效的答案。 –