将参数传递到表达式中时解构方法调用表达式 [英] deconstructing methodcallexpressions when passing parameters into the expression

查看:73
本文介绍了将参数传递到表达式中时解构方法调用表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取传递到表达式中的参数的值.系统将使用错误消息工厂,传入来自父/调用方法的值.如果我对值进行硬编码并将其传递到表达式中,则Method.Arguments数组将具有实际值,而下面的方法将提取该值.如果它是从父方法传入的,它将最终得到看起来像方法调用签名的表示形式

I am trying to get the value of the parameters passed into the expression. The system will use the error message factory, passing in values that have come from a parent / calling method. If I hard code a value and pass it into the expression the Method.Arguments array will have the actual value and the method below will extract that value. If it is passed in from a parent method it will end up getting what seems like a representation of the method call signature

.Constant<AutoValidator.Impl.Validator+<>c__DisplayClass7_0>(AutoValidator.Impl.Validator+<>c__DisplayClass7_0).minLength

我不确定我是否会错误地将这些值向下传递,还是试图错误地获取它们的实际值.

I am not sure if I am some how passing the values down incorrectly or I am trying to get the actual value of them incorrectly.

//the expression will receive the value 123
_errorMessageFactory.Get<string>((val, exp) => exp.MinLength(text, 123, message), propName);

//we pass xx which has the value of 123, but the expression doesn't show this value
var xx = 123;
_errorMessageFactory.Get<string>((val, exp) => exp.MinLength(text, xx, message), propName);

public Tuple<string, List<object>> Get<TMember>(Expression<Func<TMember, IValidatorExpression, bool>> exp, string propName)
{
            var methodCall = exp.Body as MethodCallExpression;
            var methodSignature = methodCall.Method.ToString();

GetArgumentValue(methodCall.Arguments[1]);
}

private object GetArgumentValue(Expression methodExpression)
{
    if (methodExpression.NodeType == ExpressionType.MemberAccess)
    {
        var memberExpression = (MemberExpression)methodExpression;
        return GetArgumentValue(memberExpression.Expression);
    }
    else if (methodExpression.NodeType == ExpressionType.Constant)
    {
        var constExp = methodExpression as ConstantExpression;
        return constExp?.Value;
     }
     throw new ArgumentOutOfRangeException("Unknown expression argument type");
}   

推荐答案

您可以实现自己的表达式访问器,在其中您将覆盖VisitConstant以收集有关c__DisplayClass

You can implement your own expression visitor where you will override VisitConstant to collect info about simple conststants and closured variables in c__DisplayClass

private class ValueExtractor : ExpressionVisitor
{
    private readonly Dictionary<Type, Dictionary<string, object>> anonymousFields;

    public ValueExtractor()
    {
        Arguments = new List<object>();
        anonymousFields = new Dictionary<Type, Dictionary<string, object>>();
    }

    public List<object> Arguments { get; }

    protected override Expression VisitMember(MemberExpression node)
    {
        var memberName = node.Member.Name;
        var type = node.Member.DeclaringType;

        var baseResult = base.VisitMember(node);

        if (anonymousFields.ContainsKey(type))
            Arguments.Add(anonymousFields[type][memberName]);

        return baseResult;
    }

    protected override Expression VisitConstant(ConstantExpression node)
    {
        var constantType = node.Type;
        if (constantType == typeof(int) || constantType == typeof(string)) // and so on
        {
            Arguments.Add(node.Value);
        }
        else if (IsAnonymousType(constantType) && !anonymousFields.ContainsKey(constantType))
        {
            var fields = new Dictionary<string, object>();
            anonymousFields.Add(constantType, fields);

            foreach (var field in constantType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField))
                fields.Add(field.Name, field.GetValue(node.Value));
        }

        return base.VisitConstant(node);
    }

    private static bool IsAnonymousType(Type type)
    {
        var hasSpecialChars = type.Name.Contains("<") || type.Name.Contains(">");
        return hasSpecialChars && type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), inherit: false).Any();
    }
}

用法:

public Tuple<string, List<object>> Get<TMember>(Expression<Func<TMember, IValidatorExpression, bool>> exp, string propName)
{
    var visitor = new ValueExtractor();
    visitor.Visit(exp);

    foreach (var argument in visitor.Arguments)
        Console.WriteLine(argument);

这篇关于将参数传递到表达式中时解构方法调用表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆