Autofac IComponentContext.Resolve 带参数
Autofac IComponentContext.Resolve With Parameters
如何向类型注册提供 IComponentContext 函数,其中参数可以是类型(待解析)或传入的参数?
因此,如果我有一个函数,我想将其用于注册,例如:
public static ClassTarget Resolver(ClassArg1 arg1, ClassArg2 arg2)
{
// Do something fancier than this...
return new ClassTarget(arg1, arg2);
}
如何为 ClassTarget
注册?
一个完整的例子,我目前正在使用的 hack 和有效的备用注册(正如人们所期望的那样):
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
我在文档中遗漏了另一个重载吗?
如果您必须完全在 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);
}
}
}
我猜这更接近您希望实现的目标。
如何向类型注册提供 IComponentContext 函数,其中参数可以是类型(待解析)或传入的参数?
因此,如果我有一个函数,我想将其用于注册,例如:
public static ClassTarget Resolver(ClassArg1 arg1, ClassArg2 arg2)
{
// Do something fancier than this...
return new ClassTarget(arg1, arg2);
}
如何为 ClassTarget
注册?
一个完整的例子,我目前正在使用的 hack 和有效的备用注册(正如人们所期望的那样):
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
我在文档中遗漏了另一个重载吗?
如果您必须完全在 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);
}
}
}
我猜这更接近您希望实现的目标。