我正在尝试获取传递到表达式中的参数的值。系统将使用错误消息工厂,传入来自父/调用方法的值。如果我对值进行硬编码并将其传递到表达式中,则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");
}
答案 0 :(得分:1)
您可以实现自己的表达式访问器,在其中您将覆盖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);