C# 从Linq表达式获取参数值
我有以下课程C# 从Linq表达式获取参数值,c#,linq,expression-trees,C#,Linq,Expression Trees,我有以下课程 public class MyClass { public bool Delete(Product product) { // some code. } } 现在我有一个助手类,看起来像这样 public class Helper<T, TResult> { public Type Type; public string Method; public Type[] ArgTypes; publi
public class MyClass
{
public bool Delete(Product product)
{
// some code.
}
}
现在我有一个助手类,看起来像这样
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 = ???
}
}
这似乎是一个带有字段“product”的对象类型,但我相信一定有一个更简单的解决方案
任何建议
更新
只是为了澄清,我根据我想要实现的目标修改了我的代码。在我的真实word应用程序中,我已经有了一个类,该类执行相同的操作,但没有表达式树:
var helper = new Helper(typeof(MyClass), "Delete",
new Type[] { typeof(Product) }, new object[] {product}));
我的Helper
的主要原因是在编译时检查方法签名是否有效
更新2
这是我当前的实现,有没有更好的方法来访问值,而不使用反射
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();
}
公共助手(表达式)
{
var body=(System.Linq.Expressions.MethodCallExpression)expression.body;
该类型=类型(T);
this.Method=body.Method.Name;
this.ArgTypes=body.Arguments.Select(x=>x.Type).ToArray();
var值=新列表();
foreach(body.Arguments中的变量arg)
{
值。添加(
(((ConstantExpression)exp.Expression).Value.GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.exp.Expression).Value);
);
}
this.ArgValues=values.ToArray();
}
以下是使用lambda创建委托的示例。对象实例使用名为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);
MyClass实例=新建MyClass();
//以下行不能更改为var声明
//因为C#无法推断类型。
Func deleteDelegate=p=>instance.Delete(p);
产品=新产品();
bool deleted=deleteDelegate(产品);
或者,您正在尝试创建一个自动执行curry操作的帮助器
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));
}
公共类助手
其中T:new()
{
公共TResult执行(Func methodLambda)
{
var instance=newt();
返回方法lamda(实例);
}
}
公共图书馆
{
var helper=newhelper();
var product=新产品();
执行(x=>x.Delete(product));
}
然而,我不得不说,这个问题看起来可疑地像是创建了一个帮助器类来处理WCF代理的生存期……你知道……就说……在这种情况下,我不会这么做……只是因为这种方法会将特定于WCF的代码泄漏到你的域中。这种方法工作得很好。它返回表达式的参数类型和值>
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();
}
}
private static KeyValuePair[]解析参数(表达式)
{
var body=(System.Linq.Expressions.MethodCallExpression)expression.body;
var值=新列表();
foreach(body.Arguments中的var参数)
{
var exp=ResolveMemberExpression(参数);
变量类型=参数.type;
var值=GetValue(exp);
添加(新的KeyValuePair(类型、值));
}
返回值。ToArray();
}
公共静态MemberExpression ResolveMemberExpression(表达式)
{
if(表达式为MemberExpression)
{
返回(MemberExpression)表达式;
}
else if(表达式为一元表达式)
{
//如果涉及强制转换,则表达式不是x=>x.FieldName,而是x=>Convert(x.FieldName)
返回(MemberExpression)((一元表达式)表达式)。操作数;
}
其他的
{
抛出新的NotSupportedException(expression.ToString());
}
}
私有静态对象GetValue(MemberExpression)
{
//表达式为常量表达式或字段表达式
if(exp.Expression为常量表达式)
{
返回(((ConstantExpression)exp.Expression).Value)
.GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.exp.Expression).Value);
}
else if(exp.Expression为MemberExpression)
{
返回GetValue((MemberExpression)exp.Expression);
}
其他的
{
抛出新的NotImplementedException();
}
}
您可以编译参数表达式,然后调用它来计算值:
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();
var值=新列表();
foreach(body.Arguments中的变量arg)
{
var value=Expression.Lambda(参数).Compile().DynamicInvoke();
增加(价值);
}
this.ArgValues=values.ToArray();
有什么原因不能编译表达式并执行它吗?或者这只是为了学习表达式树而胡闹?@rbev+1比我强。见鬼,为什么不直接调用Delete(product)
?@Aron,这只是一个例子,助手将被实例化并传递。@rbev:他甚至不需要表达式。一个简单的委托就足够了。OP需要澄清他的约束条件,然后才能回答这一问题。这完全不是我想要的。参数应该是foreach中声明的arg。在文章中提到编译不是快速操作。我想你的意思是(添加了一个缺少的类型参数):KeyValuePair[]ResolveArgs(Expression Expression)
@PatrickKoorevaar你是对的。在我的代码中,这个方法在一个带有类型参数的泛型类中,所以我错过了这一部分。我想我在这里显示了我的无知。为什么需要对constantExpression.Value
的结果调用GetType().GetField([name]).GetValue(constantExp.Value)
?是var v=1的.Value
属性代码>表达式不是正在分配的1吗?是由constantExpression.value
返回的表达式的对象表示形式上的字段中的文字1值吗?已经有一段时间了,但如果我没记错的话,表达式x=>x.Delete(product)
由我从获得的对象表示(constantExpression)exp.Expression).值
且此对象具有f
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();
}
}
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();