2015-06-19 84 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'处理程序或仅使用构造函数来执行实际的初始化。 –