Autofac IComponentContext.Resolve With Parameters

本文关键字:Parameters With Resolve IComponentContext Autofac | 更新日期: 2023-09-27 17:57:07

如何为类型注册提供IComponentContext 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是否只是另一个重载?

Autofac IComponentContext.Resolve With Parameters

如果您必须完全在该Resolver函数中进行初始化,则可能会使用现在的机制。也就是说,如果你有一个特定的函数,并且出于某种原因,你必须实例化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);
    }
  }
}

我猜这更接近您希望实现的目标。