C# 使用上下文信息解析谓词

C# 使用上下文信息解析谓词,c#,simple-injector,C#,Simple Injector,我有一个服务类型ITestGuard,我想用FooTestGuard或NullTestGuard实现它,具体取决于实例被注入的表达式树。具体来说,我想为所有情况提供FooTestGuard,但解析请求的“祖先”之一为TestController类型时除外 我想我可以通过ExpressionBuilding事件来实现这一点,作为指导,将新的Parent属性添加到DependencyContext并通过递归下降来填充它: [DebuggerDisplay("DependencyContext (Se

我有一个服务类型
ITestGuard
,我想用
FooTestGuard
NullTestGuard
实现它,具体取决于实例被注入的表达式树。具体来说,我想为所有情况提供
FooTestGuard
,但解析请求的“祖先”之一为
TestController
类型时除外

我想我可以通过
ExpressionBuilding
事件来实现这一点,作为指导,将新的
Parent
属性添加到
DependencyContext
并通过递归下降来填充它:

[DebuggerDisplay("DependencyContext (ServiceType: {ServiceType}, ImplementationType: {ImplementationType})")]
public class DependencyContext
{
    public static readonly DependencyContext Root = new DependencyContext();

    public DependencyContext(
        Type serviceType,
        Type implementationType,
        ParameterInfo parameter,
        DependencyContext parent = null)
    {
        ServiceType = serviceType;
        ImplementationType = implementationType;
        Parameter = parameter;
        Parent = parent;
    }

    private DependencyContext() { }

    public Type ServiceType { get; private set; }
    public Type ImplementationType { get; private set; }
    public ParameterInfo Parameter { get; private set; }
    public DependencyContext Parent { get; private set; }
}

public static class ContextDependentExtensions
{
    public static IEnumerable<DependencyContext> AncestorsAndSelf(this DependencyContext context)
    {
        while (true)
        {
            yield return context;
            if (context.Parent == null)
                yield break;
            context = context.Parent;
        }
    }

    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(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(
                    contextBasedFactory,
                    rootFactory,
                    e.RegisteredServiceType,
                    e.Expression);

                e.Expression = rewriter.Visit(e.Expression);
            }
        };
    }

    private sealed class DependencyContextRewriter : ExpressionVisitor
    {
        private readonly object _contextBasedFactory;
        private readonly object _rootFactory;
        private readonly Type _serviceType;
        private readonly Expression _expression;
        private readonly DependencyContext _parentContext;
        private readonly ParameterInfo _parameter;

        public DependencyContextRewriter(object contextBasedFactory,
            object rootFactory,
            Type serviceType,
            Expression expression,
            DependencyContext parentContext = null,
            ParameterInfo parameter = null)
        {
            _serviceType = serviceType;
            _contextBasedFactory = contextBasedFactory;
            _rootFactory = rootFactory;
            _expression = expression;
            _parentContext = parentContext;
            _parameter = parameter;
        }

        private Type ImplementationType
        {
            get
            {
                var expression = _expression as NewExpression;

                if (expression == null)
                    return _serviceType;

                return expression.Constructor.DeclaringType;
            }
        }

        protected override Expression VisitNew(NewExpression node)
        {
            var context = new DependencyContext(_serviceType, ImplementationType, _parameter, _parentContext);
            var parameters = node.Constructor.GetParameters();

            var rewritten = node.Arguments
                .Select((x, i) => new DependencyContextRewriter(_contextBasedFactory, _rootFactory, x.Type, x, context, parameters[i]).Visit(x));

            return node.Update(rewritten);
        }

        protected override Expression VisitInvocation(InvocationExpression node)
        {
            if (IsRootedContextBasedFactory(node))
                return Expression.Invoke(
                    Expression.Constant(_contextBasedFactory),
                    Expression.Constant(
                        new DependencyContext(
                            _serviceType,
                            ImplementationType,
                            _parameter,
                            new DependencyContext(_serviceType, ImplementationType, _parameter, _parentContext))));

            return base.VisitInvocation(node);
        }

        private bool IsRootedContextBasedFactory(InvocationExpression node)
        {
            var expression = node.Expression as ConstantExpression;

            if (expression == null)
                return false;

            return ReferenceEquals(expression.Value, _rootFactory);
        }
    }
}
[DebuggerDisplay(“DependencyContext(ServiceType:{ServiceType},ImplementationType:{ImplementationType})”)]
公共类依赖上下文
{
公共静态只读DependencyContext根=新DependencyContext();
公共依赖语境(
类型serviceType,
类型实现类型,
ParameterInfo参数,
DependencyContext父项=空)
{
服务类型=服务类型;
ImplementationType=ImplementationType;
参数=参数;
父母=父母;
}
私有依赖上下文(){}
公共类型ServiceType{get;private set;}
公共类型实现类型{get;private set;}
公共参数信息参数{get;private set;}
public DependencyContext父项{get;private set;}
}
公共静态类contextDependentTextensions
{
公共静态IEnumerable AnteStorsandSelf(此DependencyContext上下文)
{
while(true)
{
屈服-返回语境;
if(context.Parent==null)
屈服断裂;
context=context.Parent;
}
}
公共静态无效注册表WithContext(此容器,
Func contextBasedFactory),其中TService:class
{
if(contextBasedFactory==null)
抛出新ArgumentNullException(“contextBasedFactory”);
Func rootFactory=()=>contextBasedFactory(DependencyContext.Root);
容器。注册(rootFactory,lifesture.Transient);
//允许将Func注入父类型。
container.ExpressionBuilding+=(发送方,e)=>
{
if(例如RegisteredServiceType!=typeof(TService))
{
var rewriter=新的DependencyContextRewriter(
基于上下文的工厂,
根工厂,
e、 RegisteredServiceType,
e、 表情);
e、 表达式=重写器访问(e.Expression);
}
};
}
私有密封类DependencyContextRewriter:ExpressionVisitor
{
私有只读对象\u contextBasedFactory;
私有只读对象_rootFactory;
私有只读类型_serviceType;
私有只读表达式\u表达式;
私有只读DependencyContext\u parentContext;
私有只读参数INFO_参数;
公共依赖性ContextRewriter(对象contextBasedFactory,
对象根工厂,
类型serviceType,
表情表情,
DependencyContext parentContext=null,
ParameterInfo参数=空)
{
_服务类型=服务类型;
_contextBasedFactory=contextBasedFactory;
_rootFactory=rootFactory;
_表达式=表达式;
_parentContext=parentContext;
_参数=参数;
}
私有类型实现类型
{
得到
{
var表达式=_表达式作为NewExpression;
if(表达式==null)
返回_serviceType;
返回表达式.Constructor.DeclaringType;
}
}
受保护的重写表达式VisitNew(新建表达式节点)
{
var context=新的DependencyContext(\u serviceType,ImplementationType,\u参数,\u parentContext);
var parameters=node.Constructor.GetParameters();
var rewrited=node.Arguments
.Select((x,i)=>newDependencyContextRewriter(_-contextBasedFactory,_-rootFactory,x.Type,x,context,parameters[i])。访问(x));
返回节点。更新(重写);
}
受保护的重写表达式VisitInvocation(调用表达式节点)
{
if(IsRootedContextBasedFactory(节点))
返回表达式.Invoke(
表达式.常量(_contextBasedFactory),
表达式.常数(
新依赖上下文(
_服务类型,
实现类型,
_参数,
新的DependencyContext(_serviceType,ImplementationType,_参数,_parentContext));
返回基地。访问职业(节点);
}
私有bool IsRootedContextBasedFactory(调用表达式节点)
{
var表达式=节点。表达式为常量表达式;
if(表达式==null)
返回false;
返回ReferenceEquals(expression.Value,_rootFactory);
}
}
}
但是,我看到的是,
上下文
层次结构在传递给委托时没有完全填充。我在请求一个
TestController
时调试了访问者,然后继续执行
ITestGuard
步骤。但是,
IsRootedContextBasedFactory
检查返回false,跳过了委托替换。我认为这是因为它在先前调用
expressionbuild
时已经被替换,这意味着注册的表达式不再是
rootFactory
,因此检查失败
public class TestGuardSelector : ITestGuard
{
    private readonly Func<bool> selector;
    private readonly ITestGuard trueGuard;
    private readonly ITestGuard falseGuard;

    public TestGuardSelector(Func<bool> selector, ITestGuard trueGuard,
        ITestGuard falseGuard) {
        this.selector = selector;
        this.trueGuard = trueGuard;
        this.falseGuard = falseGuard;
    }

    public object TestGuardMethod(object value) {
        // Forward the call
        return this.CurrentGuard.TestGuardMethod(value);
    }

    private ITestGuard CurrentGuard {
        get { return this.selector() ? this.trueGuard : this.falseGuard; }
    }
}
container.RegisterSingle<ITestGuard>(new TestGuardSelector(
    () => HttpContext.Current.Request.Url.Contains(@"\Test\"),
    new FooTestGuard(),
    new NullTestGuard());