c# - 将参数传递给表达式时解构方法调用表达式
问题描述
我正在尝试获取传递给表达式的参数的值。系统将使用错误消息工厂,传入来自父/调用方法的值。如果我硬编码一个值并将其传递给表达式,Method.Arguments 数组将具有实际值,下面的方法将提取该值。如果它是从父方法传入的,它最终会得到看起来像是方法调用签名的表示
.Constant<AutoValidator.Impl.Validator+<>c__DisplayClass7_0>(AutoValidator.Impl.Validator+<>c__DisplayClass7_0).minLength
我不确定我是如何错误地传递值还是试图错误地获取它们的实际值。
//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
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);
推荐阅读
- mysql - 如何创建简单的 REST API 登录?
- excel - Excel公式查找重复值的最小值
- android - 自调用时的Android导航组件Backstack
- javascript - Kendo UI 中的验证 numericTextBox
- php - PHP 7.4 中的循环引用
- javascript - 在 Chrome 扩展中使用 NOTY JS 通知库
- python - GCP Pub/Sub Push Endpoint 在请求参数中找不到谷歌域验证令牌
- driver - 在 Ubuntu 18.04 和英特尔 XL710 上安装 DPDK
- postgresql - 如何在laravel中显示这样的数据
- java - 复利如何计算频率