[英]Get the parameter value from a Linq Expression
I have the following class 我有以下课程
public class MyClass
{
public bool Delete(Product product)
{
// some code.
}
}
Now I have a helper class that looks like this 现在我有一个看起来像这样的助手类
public class Helper<T, TResult>
{
public Type Type;
public string Method;
public Type[] ArgTypes;
public object[] ArgValues;
public Helper(Expression<Func<T, TResult>> 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 = ???
}
}
The idea ist to use this code from somewhere: 这个想法是从某个地方使用这个代码:
// I am returning a helper somewhere
public Helper<T> GetMethod<T>()
{
var product = GetProduct(1);
return new Helper<MyClass>(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<T>(Helper<T> helper)
{
var instance = new MyClass();
var Invoker = new Invoker(helper.Type, helper.Method, helper.ArgTypes, helper.ArgValues);
return (bool)Invoker.Invoke(instance);
}
The point where I am stuck is how to extract the arguments from the expression itself. 我被困的地方是如何从表达式本身中提取参数。
I found this way 我找到了这种方式
((ConstantExpression)((MemberExpression)body.Arguments[0]).Expression).Value
which seems to be an object type with a field "product" but I believe there must be a simpler solution. 这似乎是一个带有“产品”字段的对象类型,但我相信必须有一个更简单的解决方案。
Any suggestions. 有什么建议。
Update 更新
Just to clarify, I modified my code according to what I want to achive. 为了澄清,我根据我想要的内容修改了我的代码。 In my real word application I already have a class that does the same but without an expression tree:
在我的真正的单词应用程序中,我已经有一个类,但没有表达式树:
var helper = new Helper(typeof(MyClass), "Delete",
new Type[] { typeof(Product) }, new object[] {product}));
The main reason for my Helper<T>
is to have Compile-Time checking if the method signature is valid. 我的
Helper<T>
主要原因是如果方法签名有效,则进行编译时检查。
Update 2 更新2
This is my current implementation, is there a better way to acces the values, without using reflection? 这是我目前的实现,是否有更好的方法来访问值,而不使用反射?
public Helper(Expression<Func<T, TResult>> 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<object>();
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();
}
This method works pretty well. 这种方法效果很好。 It returns the argument types and values for an Expression>
它返回Expression>的参数类型和值
private static KeyValuePair<Type, object>[] ResolveArgs<T>(Expression<Func<T, object>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
var values = new List<KeyValuePair<Type, object>>();
foreach (var argument in body.Arguments)
{
var exp = ResolveMemberExpression(argument);
var type = argument.Type;
var value = GetValue(exp);
values.Add(new KeyValuePair<Type, object>(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();
}
}
You can compile the argument expression and then invoke it to calculate the value: 您可以编译参数表达式,然后调用它来计算值:
var values = new List<object>();
foreach(var arg in body.Arguments)
{
var value = Expression.Lambda(argument).Compile().DynamicInvoke();
values.Add(value);
}
this.ArgValues = values.ToArray();
Here is an example of creation of a delegate using a lambda. 以下是使用lambda创建委托的示例。 The object instance is encapsulated into the delegate using a C# feature called closure.
使用名为closure的C#功能将对象实例封装到委托中。
MyClass instance = new MyClass();
//This following line cannot be changed to var declaration
//since C# can't infer the type.
Func<Product, bool> deleteDelegate = p => instance.Delete(p);
Product product = new Product();
bool deleted = deleteDelegate(product);
Alternatively you are trying to create a Helper that automagically Currys. 或者,您正在尝试创建一个自动化Currys的Helper。
public class Helper<T>
where T : new()
{
public TResult Execute<TResult>(Func<T, TResult> methodLambda)
{
var instance = new T();
return methodLamda(instance);
}
}
public void Main()
{
var helper = new Helper<MyClass>();
var product = new Product();
helper.Execute(x => x.Delete(product));
}
However I have to say this problem looks suspiciously like the creation of a Helper class to handle the lifetime of a WCF proxy....You know...just say...in which case this ISN'T how I would approach this...simply because this approach leaks WCF specific code into your domain. 但是我不得不说这个问题看起来很像创建一个Helper类来处理WCF代理的生命周期....你知道......只是说...在这种情况下这不是我怎么接近这个...只是因为这种方法将WCF特定代码泄漏到您的域中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.