C# 简单注入器:获取图形的根
例如,我有以下对象图:C# 简单注入器:获取图形的根,c#,dependency-injection,tree,simple-injector,C#,Dependency Injection,Tree,Simple Injector,例如,我有以下对象图: new Root( new Branch(), new BranchWithLeafs( new Leaf() ) ); 让我们以Leaf为例,我可以确定Leaf的父对象使用的是什么,但如何获取Root?RegisterWithContext扩展方法在后台使用ExpressionBuilding事件,并截取Leaf父对象的表达式并进行更改调用叶的委托,以便传入依赖上下文 扩展代码以允许父级的父级(Root,在您的情况下)也被拦截是非常容易的
new Root(
new Branch(),
new BranchWithLeafs(
new Leaf()
)
);
让我们以
Leaf
为例,我可以确定Leaf
的父对象使用的是什么,但如何获取Root
?RegisterWithContext
扩展方法在后台使用ExpressionBuilding
事件,并截取Leaf
父对象的表达式
并进行更改调用叶
的委托,以便传入依赖上下文
扩展代码以允许父级的父级(Root
,在您的情况下)也被拦截是非常容易的,但不幸的是,当您使用比Transient
更长的生活方式注册服务时,这会很快中断。这是由简单喷油器在盖子下进行的优化引起的。例如,当您将分支
注册为单例时,其值在创建根
表达式之前创建,这意味着在该点上,一旦构建了根
,就没有可以更改的表达式树。因此,在这种情况下,根
仅仅依赖于一个表达式.常量
,该常量包含对分支
实例的引用,您将无法更改叶
的创建。我认为这是为数不多的几种情况之一,在这些情况下,简单的注入器确实会对您产生不利影响
下面是一个修改版的RegisterWithContext
扩展方法,它允许一路使用“海龟”,但请记住,一旦你在树中注册了与Transient
不同的生活方式,链就会被截断:
[DebuggerDisplay("DependencyContext (ServiceType: {ServiceType}, " +
"ImplementationType: {ImplementationType})")]
public class DependencyContext {
internal static readonly DependencyContext Root =
new DependencyContext();
internal DependencyContext(Type serviceType,
Type implementationType, DependencyContext parent)
{
this.ServiceType = serviceType;
this.ImplementationType = implementationType;
this.Parent = parent;
}
private DependencyContext() { }
// There's now a Parent property!
public DependencyContext Parent { get; private set; }
public Type ServiceType { get; private set; }
public Type ImplementationType { get; private set; }
}
public static class ContextDependentExtensions {
public static void RegisterWithContext<TService>(
this Container container,
Func<DependencyContext, TService> contextBasedFactory)
where TService : class {
if (contextBasedFactory == null) {
throw new ArgumentNullException("contextBasedFactory");
}
Func<TService> rootFactory =
() => contextBasedFactory(DependencyContext.Root);
container.Register<TService>(rootFactory, Lifestyle.Transient);
// Allow the Func<DependencyContext, TService> to be
// injected into parent types.
container.ExpressionBuilding += (sender, e) => {
if (e.RegisteredServiceType != typeof(TService)) {
var rewriter = new DependencyContextRewriter {
ServiceType = e.RegisteredServiceType,
ContextBasedFactory = contextBasedFactory,
RootFactory = rootFactory,
Expression = e.Expression
};
e.Expression = rewriter.Visit(e.Expression);
}
};
}
private sealed class DependencyContextRewriter : ExpressionVisitor {
internal Type ServiceType { get; set; }
internal object ContextBasedFactory { get; set; }
internal object RootFactory { get; set; }
internal Expression Expression { get; set; }
internal Type ImplementationType
{
get {
var expression = this.Expression as NewExpression;
if (expression != null) {
return expression.Constructor.DeclaringType;
}
return this.ServiceType;
}
}
protected override Expression VisitInvocation(InvocationExpression node) {
var context = GetContextFromNode(node);
if (context == null) {
return base.VisitInvocation(node);
}
return Expression.Invoke(
Expression.Constant(this.ContextBasedFactory),
Expression.Constant(
new DependencyContext(
this.ServiceType,
this.ImplementationType,
context)));
}
private DependencyContext GetContextFromNode(InvocationExpression node) {
var constant = node.Expression as ConstantExpression;
if (constant != null) {
if (object.ReferenceEquals(constant.Value, this.RootFactory)) {
return DependencyContext.Root;
}
if (object.ReferenceEquals(constant.Value, this.ContextBasedFactory)) {
var arg = (ConstantExpression)node.Arguments[0];
return (DependencyContext)(arg.Value);
}
}
return null;
}
}
}
[DebuggerDisplay(“DependencyContext(ServiceType:{ServiceType},”+
“ImplementationType:{ImplementationType})”)]
公共类依赖上下文{
内部静态只读DependencyContext根=
新的DependencyContext();
内部依赖上下文(类型serviceType,
类型implementationType,DependencyContext父级)
{
this.ServiceType=ServiceType;
this.ImplementationType=ImplementationType;
这个。父=父;
}
私有依赖上下文(){}
//现在有了一个父属性!
public DependencyContext父项{get;private set;}
公共类型ServiceType{get;private set;}
公共类型实现类型{get;private set;}
}
公共静态类contextDependentTextensions{
公共静态无效注册表WithContext(
这个集装箱,
Func contextBasedFactory)
where-TService:class{
if(contextBasedFactory==null){
抛出新ArgumentNullException(“contextBasedFactory”);
}
Func根工厂=
()=>contextBasedFactory(DependencyContext.Root);
容器。注册(rootFactory,lifesture.Transient);
//允许使用Func
//注入父类型。
container.ExpressionBuilding+=(发送方,e)=>{
if(例如RegisteredServiceType!=typeof(TService)){
var rewriter=新的DependencyContextRewriter{
ServiceType=e.RegisteredServiceType,
ContextBasedFactory=ContextBasedFactory,
RootFactory=RootFactory,
表达式
};
e、 表达式=重写器访问(e.Expression);
}
};
}
私有密封类DependencyContextRewriter:ExpressionVisitor{
内部类型ServiceType{get;set;}
内部对象ContextBasedFactory{get;set;}
内部对象根工厂{get;set;}
内部表达式{get;set;}
内部类型实现类型
{
得到{
var expression=this.expression作为NewExpression;
if(表达式!=null){
返回表达式.Constructor.DeclaringType;
}
返回此.ServiceType;
}
}
受保护的重写表达式VisitInvocation(调用表达式节点){
var context=GetContextFromNode(节点);
if(上下文==null){
返回基地。访问职业(节点);
}
返回表达式.Invoke(
Expression.Constant(this.ContextBasedFactory),
表达式.常数(
新依赖上下文(
这个.ServiceType,
这个.ImplementationType,
),;
}
private DependencyContext GetContextFromNode(调用表达式节点){
var常量=节点。表达式为常量表达式;
if(常数!=null){
if(object.ReferenceEquals(constant.Value,this.RootFactory)){
返回DependencyContext.Root;
}
if(object.ReferenceEquals(constant.Value,this.ContextBasedFactory)){
var arg=(ConstantExpression)node.Arguments[0];
返回(DependencyContext)(参数值);
}
}
返回null;
}
}
}
通过对分支
和分支WithLeafs
使用上下文相关注入?如果它与Leaf
一起工作,那么它应该与更高级别一起工作。@Robert这是一个非常简单的示例。在我的场景中,节点的数量及其生命周期各不相同。是的,但机制不应该如此。基本上,这将是一个递归操作,对吗?如果是的话,你应该能够一直走到树的根部。这实际上是相当复杂的。你能更新你的问题来解释你想要达到的目标吗。也许还有另一种(或更好的)方法。@RobertHarvey:这是一个相当复杂的问题