C# Autofac IComponentContext。使用参数解析

C# Autofac IComponentContext。使用参数解析,c#,inversion-of-control,autofac,C#,Inversion Of Control,Autofac,如果参数可以是类型(待解析)或传入的参数,如何为类型注册提供IComponentContext func 因此,如果我有一个func,我想用于注册,例如: public static ClassTarget Resolver(ClassArg1 arg1, ClassArg2 arg2) { // Do something fancier than this... return new ClassTarget(arg1, arg2); }

如果参数可以是类型(待解析)或传入的参数,如何为类型注册提供IComponentContext func

因此,如果我有一个func,我想用于注册,例如:

    public static ClassTarget Resolver(ClassArg1 arg1, ClassArg2 arg2)
    {
        // Do something fancier than this...
        return new ClassTarget(arg1, arg2);
    }
我如何为
ClassTarget
注册它

一个完整的例子,我目前正在使用的hack和其他有效的注册(正如人们所期望的):

公共类类arg1{}
公共类类arg2{}
公共类目标
{
公共类目标(类arg1 arg1,类arg2 arg2){}
}
公共静态类测试
{
公共静态类目标解析程序(类arg1 arg1、类arg2 arg2)
{
//做些比这更有趣的事。。。
返回新的类目标(arg1、arg2);
}
私有静态T GetArgValue(IComponentContext componentContext,IEnumerable参数)
{
if(参数!=null)
{
var param=parameters.OfType().FirstOrDefault(p=>p.Type==typeof(T));
如果(参数!=null)
{
返回(T)参数值;
}
}
返回componentContext.Resolve();
}
公共静态无效测试()
{
var builder=new ContainerBuilder();
//第一个参数将正常解决
builder.RegisterType().AsSelf().SingleInstance();
//Works-只是一个典型的类型注册,没有使用Func
//builder.RegisterType().AsSelf().SingleInstance();
//有效-但前提是我们知道如何将参数解析为类型或参数
//builder.Register((c,p)=>Resolver(c.Resolve(),p.TypedAs()).AsSelf().SingleInstance();
//工作-气味虽然!
Register((c,p)=>Resolver(GetArgValue(c,p),GetArgValue(c,p))).AsSelf().SingleInstance();
//构建/范围
var context=builder.Build();
var scope=context.BeginLifetimeScope();
//第二个参数在解析时作为实例/参数传递
解析(新的类型参数(typeof(ClassArg2),新的ClassArg2());
}
}

显然,我误解了这里的核心部分,因为我自己在做参数解析时遇到了麻烦,而Autofac通常会无缝地进行参数解析!文档中缺少的
解析
是否还有另一个重载?

如果您必须完全在
解析程序
函数中进行初始化,您可能无法使用现在的机制。也就是说,如果您有一个特定的函数,并且出于任何原因,您必须同时实例化
ClassTarget
对象,并且必须在那里初始化它,这样您就卡住了

如果您可以重构一点,就可以利用Autofac的功能发挥优势。

下面是一个示例,说明了如果您稍微进行重构并使用委托工厂功能,代码可能会是什么样子:

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);
    }
  }
}
公共类类arg1{}
公共类类arg2{}
公共类目标
{
//使用所需的参数集创建代理工厂
//在解析操作期间-Autofac不会自动填充的内容。
公共委托类目标工厂(类arg2 arg2);
//构造函数可以具有所有必需的参数。请确保
//此处的名称与代理工厂中的名称匹配。
公共类目标(类arg1 arg1,类arg2 arg2){}
//只是为了显示初始化工作。
公共布尔值已初始化{get;set;}
}
公共静态类测试
{
公共静态void初始化(类目标)
{
//让Autofac来做,而不是在这里更新类目标
//通过代理工厂并*仅*在此处进行初始化-
//你之前提到的“更喜欢的东西”。
target.i初始化=真;
}
公共静态无效测试()
{
//注册由Autofac填充的参数。
var builder=new ContainerBuilder();
builder.RegisterType().AsSelf().SingleInstance();
//注册ClassTarget,Autofac将看到工厂代理。
已激活(args=>Initialize(args.Instance));
var context=builder.Build();
使用(var scope=context.BeginLifetimeScope())
{
//解析工厂委托,而不是直接解析类。
var factory=scope.Resolve();
var classTarget=factory(新类arg2());
//你需要什么就做什么。
WriteLine(“ClassTarget已初始化?{0}”,ClassTarget.IsInitialized);
}
}
}

我猜这与您希望实现的目标有点接近。

代表工厂的观点-这显然更像Autofac。但我真正希望实现的是让Autofac解析func参数,不管它是类型还是解析参数——基本上删除GetArgValue调用——类似于如果我根本没有func,而我只是使用类构造函数(我可以,也应该在这里这么做)。当您使用实例参数进行解析(如果您不处理IComponentContext表单)时,是否需要委托工厂?无论是好是坏,在自动填充参数时,Autofac都与反射有着很好的联系,无论这些参数是构造函数参数还是要设置的属性。如果你能使用构造函数,就这么做吧。您可能还对这个问题感兴趣。更重要的一点是-尝试将对象的实例化与初始化分离。我猜您在
解析器
中的复杂逻辑更多的是关于初始化而不是实例化。让Autofac实例化,然后使用一个激活的
处理程序或仅使用构造函数来进行实际初始化。是的,你完全正确,这可能是核心问题。(仍在使用其他示例进行确认。)参考
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);
    }
  }
}