2015-06-19 75 views
1

如何將一個IComponentContext函數提供給類型註冊,其中參數可以是類型(將被解析)或參數傳入?Autofac IComponentContext.Resolve With Parameters

所以,如果我有一個FUNC我想使用註冊像這樣:

public static ClassTarget Resolver(ClassArg1 arg1, ClassArg2 arg2) 
    { 
     // Do something fancier than this... 
     return new ClassTarget(arg1, arg2); 
    } 

我將如何登記,對ClassTarget

完整的例子,與我目前使用的工作(如人們所期望的)黑客和替代登記:

public class ClassArg1 { } 

public class ClassArg2 { } 

public class ClassTarget 
{ 
    public ClassTarget(ClassArg1 arg1, ClassArg2 arg2) { } 
} 

public static class ResolveFuncTest 
{ 
    public static ClassTarget Resolver(ClassArg1 arg1, ClassArg2 arg2) 
    { 
     // Do something fancier than this... 
     return new ClassTarget(arg1, arg2); 
    } 

    private static T GetArgValue<T>(IComponentContext componentContext, IEnumerable<Parameter> parameters) 
    { 
     if (parameters != null) 
     { 
      var param = parameters.OfType<TypedParameter>().FirstOrDefault(p => p.Type == typeof(T)); 
      if (param != null) 
      { 
       return (T)param.Value; 
      } 
     } 

     return componentContext.Resolve<T>(); 
    } 

    public static void Test() 
    { 
     var builder = new ContainerBuilder(); 

     // The first argument will be resolved as normal 
     builder.RegisterType<ClassArg1>().AsSelf().SingleInstance(); 

     // Works - just a typical type registration without the Func used 
     //builder.RegisterType<ClassTarget>().AsSelf().SingleInstance(); 
     // Works - but only if we know how to resolve the arguments as types or parameters 
     //builder.Register((c, p) => Resolver(c.Resolve<ClassArg1>(), p.TypedAs<ClassArg2>())).AsSelf().SingleInstance(); 
     // Works - smells though! 
     builder.Register((c, p) => Resolver(GetArgValue<ClassArg1>(c,p), GetArgValue<ClassArg2>(c, p))).AsSelf().SingleInstance(); 

     // Build/scope 
     var context = builder.Build(); 
     var scope = context.BeginLifetimeScope(); 

     // The second argument is passed as an instance/parameter at resolve time 
     scope.Resolve<ClassTarget>(new TypedParameter(typeof(ClassArg2), new ClassArg2())); 
    } 
} 

顯然,我在這裏誤解核心的東西,因爲我絆倒自己做Autofac通常無縫的參數分辨率!是否有另一個超載Resolve我在文檔中丟失?

回答

2

如果您必須完全在Resolver函數中完成初始化,那麼您可能會停留在使用現在的機制。也就是說,如果你有一個特定的功能,並且無論出於何種原因,你必須同時實例化ClassTarget對象你必須在那裏初始化它,那麼你就被卡住了。

如果你可以重構一下,你可以使用Autofac的delegate factories功能。

這裏是什麼樣的代碼可能看起來一樣,如果你重構了一下,使用委託工廠功能的例子:

public class ClassArg1 { } 

public class ClassArg2 { } 

public class ClassTarget 
{ 
    // Create a delegate factory with the set of parameters you require 
    // during the Resolve operation - things that won't be auto-filled by Autofac. 
    public delegate ClassTarget Factory(ClassArg2 arg2); 

    // The constructor can have all the required parameters. Make sure the 
    // names here match the names in the delegate factory. 
    public ClassTarget(ClassArg1 arg1, ClassArg2 arg2) { } 

    // Just something to show the initalization working. 
    public bool IsInitialized { get; set; } 
} 

public static class ResolveFuncTest 
{ 
    public static void Initialize(ClassTarget target) 
    { 
    // Instead of newing up the ClassTarget here, let Autofac do that 
    // through the delegate factory and *only* do initialization here - 
    // the "something fancier" you previously alluded to. 
    target.IsInitialized = true; 
    } 

    public static void Test() 
    { 
    // Register the argument that gets populated by Autofac. 
    var builder = new ContainerBuilder(); 
    builder.RegisterType<ClassArg1>().AsSelf().SingleInstance(); 

    // Register the ClassTarget and Autofac will see the factory delegate. 
    builder.RegisterType<ClassTarget>().OnActivated(args => Initialize(args.Instance)); 

    var context = builder.Build(); 
    using(var scope = context.BeginLifetimeScope()) 
    { 
     // Resolve a factory delegate rather than resolving the class directly. 
     var factory = scope.Resolve<ClassTarget.Factory>(); 
     var classTarget = factory(new ClassArg2()); 

     // Do whatever you need. 
     Console.WriteLine("ClassTarget is initialized? {0}", classTarget.IsInitialized); 
    } 
    } 
} 

我猜這是一個有點接近你希望達到什麼樣的。

+0

點代表工廠 - 這絕對看起來更像Autofac。我真正希望實現的是讓Autofac解決func參數,而不管它是一個類型還是解析參數 - 基本上移除GetArgValue調用 - 類似於我根本沒有func,而且我只是在使用這個類的構造函數(我可以,而且可以承認,這可能應該在這裏做)。當您使用實例參數來解析時(如果您不處理IComponentContext表單),是否需要委託工廠? – Gene

+0

無論好壞,Autofac都可以很好地與反射聯繫起來,當涉及到自動填充參數時 - 無論是構造函數參數還是要設置的屬性。如果你可以使用構造函數,就這樣做。您可能也對[隱式關係類型'Func ]感興趣(http://autofac.readthedocs.org/en/latest/resolve/relationships.html#parameterized-instantiation-func-x-y-b)。 –

+0

較大的一點是 - 嘗試從初始化中分離對象的實例。我猜你在'Resolver'中的複雜邏輯更多地是關於初始化而不是實例化。讓Autofac實例化,然後使用'OnActivated'處理程序或僅使用構造函數來執行實際的初始化。 –