如何使用被解析的类型来解析依赖
How to use the type being resolved to resolve a dependency
我有几个 类 依赖类型 ILogger
。 ILogger
的实现需要知道它是记录器的类型,即 Foo
的 ILogger
将是 new Logger(typeof(Foo))
,Bar
将是new Logger(typeof(Bar))
,等等
我希望 Unity 自动注入适当的记录器;换句话说,当我调用 container.Resolve<Foo>()
时,我希望将 new Logger(typeof(Foo))
注入到 Foo
实例中。
如何在 Unity 中进行设置?有没有办法将正在解析的类型传递给依赖项?
(在我的真实代码中,我实际上有一个 ILoggerFactory
和一个 Create
方法,它也将类型作为参数。所以我可以将工厂传递给我的 类,他们会自己调用 Create
来获得合适的记录器,但它并不像我想要实现的那样优雅)
一些使事情更清楚的代码:
interface ILogger
{
...
}
class Logger : ILogger
{
private readonly Type _type;
public Logger(Type type)
{
_type = type;
}
...
}
class Foo
{
private readonly ILogger _logger;
public Foo(ILogger logger) // here I want a Logger with its type set to Foo
{
_logger = logger;
}
}
这个 准确地展示了我正在尝试做的事情,而被接受的答案正是我正在寻找的东西......但它是针对 NInject,而不是 Unity .
正如@spotco 所建议的,我也推荐仿制药。统一注册将使用 "open generics" 完成,如此处所示。这种单一注册使您能够解析 Logger 的泛型参数中的任何类型。
unityContainer.RegisterType(typeof(ILogger<>), typeof(Logger<>));
使用该注册,您可以像这样使用构造函数注入来解析实例。
public class MyClass
{
public MyClass(ILogger<MyClass> logger) { ... }
}
这是一个容器扩展,它将 Logger 构造函数的 Type 参数设置为 ILogger 注入的类型。
瞬态 IBuilderContext.Policies 用于存储 ILogger 注入的类型。
也许它比需要的更复杂,但这似乎有效
public class LoggerExtension : UnityContainerExtension
{
public static NamedTypeBuildKey LoggerBuildKey = new NamedTypeBuildKey<Logger>();
protected override void Initialize()
{
Context.Strategies.Add(new LoggerTrackingPolicy(), UnityBuildStage.TypeMapping);
Context.Strategies.Add(new LoggerBuildUpStrategy(), UnityBuildStage.PreCreation);
}
}
public class LoggerTrackingPolicy : BuilderStrategy
{
public LoggerTrackingPolicy()
{
}
public override void PreBuildUp(IBuilderContext context)
{
if (context.BuildKey.Type != typeof(Logger))
{
var loggerPolicy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey);
if (loggerPolicy == null)
{
loggerPolicy = new LoggerPolicy();
context.Policies.Set<ILoggerPolicy>(loggerPolicy, LoggerExtension.LoggerBuildKey);
}
loggerPolicy.Push(context.BuildKey.Type);
}
}
}
public class LoggerBuildUpStrategy : BuilderStrategy
{
public LoggerBuildUpStrategy()
{
}
public override void PreBuildUp(IBuilderContext context)
{
if (context.BuildKey.Type == typeof(Logger))
{
var policy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey);
Type type = policy.Peek();
if (type != null)
{
context.AddResolverOverrides(new ParameterOverride("type", new InjectionParameter(typeof(Type), type)));
}
}
}
public override void PostBuildUp(IBuilderContext context)
{
if (context.BuildKey.Type != typeof(Logger))
{
var policy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey);
policy.Pop();
}
}
}
public interface ILoggerPolicy : IBuilderPolicy
{
void Push(Type type);
Type Pop();
Type Peek();
}
public class LoggerPolicy : ILoggerPolicy
{
private Stack<Type> types = new Stack<Type>();
public void Push(Type type)
{
types.Push(type);
}
public Type Peek()
{
if (types.Count > 0)
{
return types.Peek();
}
return null;
}
public Type Pop()
{
if (types.Count > 0)
{
return types.Pop();
}
return null;
}
}
它的工作原理是:当尝试解析不是 Logger 的类型时,在 TypeMapping 阶段(在任何创建之前),该类型被压入堆栈。稍后,在创建之前,如果类型是 Logger,那么它被注入的类型将从堆栈中窥视,并且该类型用作解析器覆盖。创建后,如果类型不是Logger,则出栈。
还有一些代码来确保它正常工作(我向记录器添加了一个类型 属性 只是为了验证它是否设置正确):
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, Logger>();
container.AddNewExtension<LoggerExtension>();
var a = container.Resolve<A>();
var b = container.Resolve<B>();
var c = container.Resolve<C>();
var d = container.Resolve<D>();
var x = container.Resolve<X>();
}
}
public interface ILogger
{
Type Type { get; }
}
public class Logger : ILogger
{
private readonly Type _type;
public Logger(Type type)
{
_type = type;
}
public Type Type { get { return _type; } }
}
public class A
{
public A(ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(A));
}
}
public class B
{
public B(ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(B));
}
}
public class C
{
public C(A a, D d, B b, ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(C));
}
}
public class D
{
public D()
{
}
}
public class X
{
public X(Y y)
{
}
}
public class Y
{
public Y(ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(Y));
}
}
我有几个 类 依赖类型 ILogger
。 ILogger
的实现需要知道它是记录器的类型,即 Foo
的 ILogger
将是 new Logger(typeof(Foo))
,Bar
将是new Logger(typeof(Bar))
,等等
我希望 Unity 自动注入适当的记录器;换句话说,当我调用 container.Resolve<Foo>()
时,我希望将 new Logger(typeof(Foo))
注入到 Foo
实例中。
如何在 Unity 中进行设置?有没有办法将正在解析的类型传递给依赖项?
(在我的真实代码中,我实际上有一个 ILoggerFactory
和一个 Create
方法,它也将类型作为参数。所以我可以将工厂传递给我的 类,他们会自己调用 Create
来获得合适的记录器,但它并不像我想要实现的那样优雅)
一些使事情更清楚的代码:
interface ILogger
{
...
}
class Logger : ILogger
{
private readonly Type _type;
public Logger(Type type)
{
_type = type;
}
...
}
class Foo
{
private readonly ILogger _logger;
public Foo(ILogger logger) // here I want a Logger with its type set to Foo
{
_logger = logger;
}
}
这个
正如@spotco 所建议的,我也推荐仿制药。统一注册将使用 "open generics" 完成,如此处所示。这种单一注册使您能够解析 Logger 的泛型参数中的任何类型。
unityContainer.RegisterType(typeof(ILogger<>), typeof(Logger<>));
使用该注册,您可以像这样使用构造函数注入来解析实例。
public class MyClass
{
public MyClass(ILogger<MyClass> logger) { ... }
}
这是一个容器扩展,它将 Logger 构造函数的 Type 参数设置为 ILogger 注入的类型。
瞬态 IBuilderContext.Policies 用于存储 ILogger 注入的类型。
也许它比需要的更复杂,但这似乎有效
public class LoggerExtension : UnityContainerExtension
{
public static NamedTypeBuildKey LoggerBuildKey = new NamedTypeBuildKey<Logger>();
protected override void Initialize()
{
Context.Strategies.Add(new LoggerTrackingPolicy(), UnityBuildStage.TypeMapping);
Context.Strategies.Add(new LoggerBuildUpStrategy(), UnityBuildStage.PreCreation);
}
}
public class LoggerTrackingPolicy : BuilderStrategy
{
public LoggerTrackingPolicy()
{
}
public override void PreBuildUp(IBuilderContext context)
{
if (context.BuildKey.Type != typeof(Logger))
{
var loggerPolicy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey);
if (loggerPolicy == null)
{
loggerPolicy = new LoggerPolicy();
context.Policies.Set<ILoggerPolicy>(loggerPolicy, LoggerExtension.LoggerBuildKey);
}
loggerPolicy.Push(context.BuildKey.Type);
}
}
}
public class LoggerBuildUpStrategy : BuilderStrategy
{
public LoggerBuildUpStrategy()
{
}
public override void PreBuildUp(IBuilderContext context)
{
if (context.BuildKey.Type == typeof(Logger))
{
var policy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey);
Type type = policy.Peek();
if (type != null)
{
context.AddResolverOverrides(new ParameterOverride("type", new InjectionParameter(typeof(Type), type)));
}
}
}
public override void PostBuildUp(IBuilderContext context)
{
if (context.BuildKey.Type != typeof(Logger))
{
var policy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey);
policy.Pop();
}
}
}
public interface ILoggerPolicy : IBuilderPolicy
{
void Push(Type type);
Type Pop();
Type Peek();
}
public class LoggerPolicy : ILoggerPolicy
{
private Stack<Type> types = new Stack<Type>();
public void Push(Type type)
{
types.Push(type);
}
public Type Peek()
{
if (types.Count > 0)
{
return types.Peek();
}
return null;
}
public Type Pop()
{
if (types.Count > 0)
{
return types.Pop();
}
return null;
}
}
它的工作原理是:当尝试解析不是 Logger 的类型时,在 TypeMapping 阶段(在任何创建之前),该类型被压入堆栈。稍后,在创建之前,如果类型是 Logger,那么它被注入的类型将从堆栈中窥视,并且该类型用作解析器覆盖。创建后,如果类型不是Logger,则出栈。
还有一些代码来确保它正常工作(我向记录器添加了一个类型 属性 只是为了验证它是否设置正确):
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, Logger>();
container.AddNewExtension<LoggerExtension>();
var a = container.Resolve<A>();
var b = container.Resolve<B>();
var c = container.Resolve<C>();
var d = container.Resolve<D>();
var x = container.Resolve<X>();
}
}
public interface ILogger
{
Type Type { get; }
}
public class Logger : ILogger
{
private readonly Type _type;
public Logger(Type type)
{
_type = type;
}
public Type Type { get { return _type; } }
}
public class A
{
public A(ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(A));
}
}
public class B
{
public B(ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(B));
}
}
public class C
{
public C(A a, D d, B b, ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(C));
}
}
public class D
{
public D()
{
}
}
public class X
{
public X(Y y)
{
}
}
public class Y
{
public Y(ILogger logger)
{
System.Diagnostics.Debug.Assert(logger.Type == typeof(Y));
}
}