从Linq表达式获取参数值
我有以下课程
public class MyClass { public bool Delete(Product product) { // some code. } }
现在我有一个看起来像这样的助手类
public class Helper { public Type Type; public string Method; public Type[] ArgTypes; public object[] ArgValues; public Helper(Expression<Func> expression) { var body = (System.Linq.Expressions.MethodCallExpression)expression.Body; this.Type = typeof(T); this.Method = body.Method.Name; this.ArgTypes = body.Arguments.Select(x => x.Type).ToArray(); this.ArgValues = ??? } }
这个想法是从某个地方使用这个代码:
// I am returning a helper somewhere public Helper GetMethod() { var product = GetProduct(1); return new Helper(x => x.Delete(product)); } // some other class decides, when to execute the helper // Invoker already exists and is responsible for executing the method // that is the main reason I don't just comile and execute my Expression public bool ExecuteMethod(Helper helper) { var instance = new MyClass(); var Invoker = new Invoker(helper.Type, helper.Method, helper.ArgTypes, helper.ArgValues); return (bool)Invoker.Invoke(instance); }
我被困的地方是如何从表达式本身中提取参数。
我找到了这种方式
((ConstantExpression)((MemberExpression)body.Arguments[0]).Expression).Value
这似乎是一个带有“产品”字段的对象类型,但我相信必须有一个更简单的解决方案。
有什么建议。
更新
为了澄清,我根据我想要的内容修改了我的代码。 在我真正的单词应用程序中,我已经有一个类,但没有表达式树:
var helper = new Helper(typeof(MyClass), "Delete", new Type[] { typeof(Product) }, new object[] {product}));
我的Helper
主要原因是如果方法签名有效,则进行编译时检查。
更新2
这是我目前的实现,是否有更好的方法来访问值,而不使用reflection?
public Helper(Expression<Func> expression) { var body = (System.Linq.Expressions.MethodCallExpression)expression.Body; this.Type = typeof(T); this.Method = body.Method.Name; this.ArgTypes = body.Arguments.Select(x => x.Type).ToArray(); var values = new List(); foreach(var arg in body.Arguments) { values.Add( (((ConstantExpression)exp.Expression).Value).GetType() .GetField(exp.Member.Name) .GetValue(((ConstantExpression)exp.Expression).Value); ); } this.ArgValues = values.ToArray(); }
这种方法效果很好。 它返回Expression>的参数类型和值
private static KeyValuePair[] ResolveArgs(Expression> expression) { var body = (System.Linq.Expressions.MethodCallExpression)expression.Body; var values = new List>(); foreach (var argument in body.Arguments) { var exp = ResolveMemberExpression(argument); var type = argument.Type; var value = GetValue(exp); values.Add(new KeyValuePair(type, value)); } return values.ToArray(); } public static MemberExpression ResolveMemberExpression(Expression expression) { if (expression is MemberExpression) { return (MemberExpression)expression; } else if (expression is UnaryExpression) { // if casting is involved, Expression is not x => x.FieldName but x => Convert(x.Fieldname) return (MemberExpression)((UnaryExpression)expression).Operand; } else { throw new NotSupportedException(expression.ToString()); } } private static object GetValue(MemberExpression exp) { // expression is ConstantExpression or FieldExpression if (exp.Expression is ConstantExpression) { return (((ConstantExpression)exp.Expression).Value) .GetType() .GetField(exp.Member.Name) .GetValue(((ConstantExpression)exp.Expression).Value); } else if (exp.Expression is MemberExpression) { return GetValue((MemberExpression)exp.Expression); } else { throw new NotImplementedException(); } }
您可以编译参数表达式,然后调用它来计算值:
var values = new List
以下是使用lambda创建委托的示例。 使用名为closure的C#特性将对象实例封装到委托中。
MyClass instance = new MyClass(); //This following line cannot be changed to var declaration //since C# can't infer the type. Func deleteDelegate = p => instance.Delete(p); Product product = new Product(); bool deleted = deleteDelegate(product);
或者,您正在尝试创建一个自动化Currys的助手。
public class Helper where T : new() { public TResult Execute(Func methodLambda) { var instance = new T(); return methodLamda(instance); } } public void Main() { var helper = new Helper(); var product = new Product(); helper.Execute(x => x.Delete(product)); }
但是我不得不说这个问题看起来很像创建一个Helper类来处理WCF代理的生命周期….你知道……只是说…在这种情况下这不是我怎么会接近这个…只是因为这种方法将WCF特定代码泄漏到您的域中。