Linq 转换表达式树类型
我一直在寻找解决问题的办法 我已经找到了一些简单表达的答案,比如Linq 转换表达式树类型,linq,expression-trees,Linq,Expression Trees,我一直在寻找解决问题的办法 我已经找到了一些简单表达的答案,比如 var exp1 Expression<Func<T, bool>> x => x.Name == "MyName" var exp1表达式x=>x.Name==“MyName” 但当表达方式如下时,我遇到了麻烦: var exp1 Expression<Func<T, bool>> x => x.Category.Name == "Coupe" var exp1表
var exp1 Expression<Func<T, bool>> x => x.Name == "MyName"
var exp1表达式x=>x.Name==“MyName”
但当表达方式如下时,我遇到了麻烦:
var exp1 Expression<Func<T, bool>> x => x.Category.Name == "Coupe"
var exp1表达式x=>x.Category.Name==“Coupe”
对于简单的表达式,我可以将任何表达式从一种类型(T)转换为另一种类型(TT),在其他更复杂的情况下,我也需要这样做
有谁能帮我指点一下吗?以下是我到目前为止得到的信息:
private class CustomVisitor<T> : ExpressionVisitor
{
private readonly ParameterExpression mParameter;
public CustomVisitor(ParameterExpression parameter)
{
mParameter = parameter;
}
//this method replaces original parameter with given in constructor
protected override Expression VisitParameter(ParameterExpression node)
{
return mParameter;
}
private int counter = 0;
/// <summary>
/// Visits the children of the <see cref="T:System.Linq.Expressions.MemberExpression" />.
/// </summary>
/// <param name="node">The expression to visit.</param>
/// <returns>
/// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
/// </returns>
/// <exception cref="System.NotImplementedException"></exception>
protected override Expression VisitMember(MemberExpression node)
{
counter++;
System.Diagnostics.Debug.WriteLine("{0} - {1}", node.ToString(), counter);
try
{
//only properties are allowed if you use fields then you need to extend
// this method to handle them
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotImplementedException();
//name of a member referenced in original expression in your
//sample Id in mine Prop
var memberName = node.Member.Name;
//find property on type T (=PersonData) by name
var otherMember = typeof(T).GetProperty(memberName);
//visit left side of this expression p.Id this would be p
var inner = Visit(node.Expression);
return Expression.Property(inner, otherMember);
}
catch (Exception ex)
{
return null;
}
}
}
私有类CustomVisitor:ExpressionVisitor
{
私有只读参数expression mpareter;
公共CustomVisitor(参数Expression参数)
{
mParameter=参数;
}
//此方法将原始参数替换为构造函数中给定的参数
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
返回参数;
}
专用整数计数器=0;
///
///探望孩子们。
///
///要访问的表达式。
///
///如果修改了表达式或任何子表达式,则返回修改后的表达式;否则返回原始表达式。
///
///
受保护的重写表达式VisitMember(MemberExpression节点)
{
计数器++;
System.Diagnostics.Debug.WriteLine(“{0}-{1}”,node.ToString(),counter);
尝试
{
//如果使用字段,则只允许使用属性,然后需要扩展
//这个方法可以处理它们
if(node.Member.MemberType!=System.Reflection.MemberTypes.Property)
抛出新的NotImplementedException();
//中原始表达式中引用的成员的名称
//矿井道具中的样本Id
var memberName=node.Member.Name;
//按名称查找类型T(=PersonData)上的属性
var otherMember=typeof(T).GetProperty(memberName);
//访问此表达式的左侧p。Id这将是p
var inner=Visit(node.Expression);
返回表达式.Property(内部,其他成员);
}
捕获(例外情况除外)
{
返回null;
}
}
}
实用方法:
public static Expression<Func<TDestin, T>> ConvertTypesInExpression<TSource, TDestin, T>(Expression<Func<TSource, T>> source)
{
var param = Expression.Parameter(typeof(TDestin));
var body = new CustomVisitor<TDestin>(param).Visit(source.Body);
Expression<Func<TDestin, T>> lambda = Expression.Lambda<Func<TDestin, T>>(body, param);
return lambda;
}
公共静态表达式ConvertTypesExpression(表达式源)
{
var param=表达式参数(typeof(TDestin));
var body=新CustomVisitor(param.Visit)(source.body);
表达式lambda=表达式.lambda(body,param);
返回lambda;
}
它的用途如下:
var changedFilter = ConvertTypesInExpression<ClientNotificationRuleDto, ClientNotificationRule, bool>(filterExpression);
var changedFilter=ConvertTypesInExpression(过滤器表达式);
因此,如果有人能提供一些想法或建议,那就太好了 分析此测试:
class Replaced
{
public Inner Inner { get; set; }
}
class Inner
{
public string Name { get; set; }
}
class Replacing
{
public Inner Inner { get; set; }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var parameter = Expression.Parameter(typeof(Replacing));
var visitor = new CustomVisitor(parameter);
Expression<Func<Replaced, bool>> expression = x => x.Inner.Name == "ss";
var resultExpression = (Expression<Func<Replacing, bool>>)visitor.Visit(expression);
var function = resultExpression.Compile();
var result = function(new Replacing
{
Inner = new Inner
{
Name = "ss"
}
});
Assert.IsTrue(result);
}
}
internal class CustomVisitor : ExpressionVisitor
{
private readonly ParameterExpression mParameter;
private int counter = 0;
public CustomVisitor(ParameterExpression parameter)
{
mParameter = parameter;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda(
Visit(node.Body),
node.Parameters.Select(x => (ParameterExpression)Visit(x)).ToArray());
//or simpler but less generic
//return Expression.Lambda(Visit(node.Body), mParameter);
}
//this method will be called twice first for Name and then for Inner
protected override Expression VisitMember(MemberExpression node)
{
counter++;
System.Diagnostics.Debug.WriteLine("{0} - {1}", node.ToString(), counter);
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotImplementedException();
var memberName = node.Member.Name;
var inner = Visit(node.Expression);
var otherMember = inner.Type.GetProperty(memberName);
return Expression.Property(inner, otherMember);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return mParameter;
}
}
类被替换
{
公共内部{get;set;}
}
班级内部
{
公共字符串名称{get;set;}
}
类替换
{
公共内部{get;set;}
}
[测试类]
公共类UnitTest1
{
[测试方法]
公共void TestMethod1()
{
var参数=Expression.parameter(typeof(replacement));
var visitor=新CustomVisitor(参数);
Expression=x=>x.Inner.Name==“ss”;
var resultExpression=(表达式)visitor.Visit(表达式);
var function=resultExpression.Compile();
var结果=功能(新功能)
{
内部=新内部
{
Name=“ss”
}
});
断言(结果);
}
}
内部类CustomVisitor:ExpressionVisitor
{
私有只读参数expression mpareter;
专用整数计数器=0;
公共CustomVisitor(参数Expression参数)
{
mParameter=参数;
}
受保护的重写表达式VisitLambda(表达式节点)
{
返回表达式.Lambda(
访问(节点体),
node.Parameters.Select(x=>(ParameterExpression)Visit(x)).ToArray();
//或者更简单但不太通用
//返回表达式.Lambda(访问(node.Body),mParameter);
}
//此方法将被调用两次,首先调用Name,然后调用internal
受保护的重写表达式VisitMember(MemberExpression节点)
{
计数器++;
System.Diagnostics.Debug.WriteLine(“{0}-{1}”,node.ToString(),counter);
if(node.Member.MemberType!=System.Reflection.MemberTypes.Property)
抛出新的NotImplementedException();
var memberName=node.Member.Name;
var inner=Visit(node.Expression);
var otherMember=inner.Type.GetProperty(memberName);
返回表达式.Property(内部,其他成员);
}
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
返回参数;
}
}
请注意,访问成员会被调用两次,并且必须对两次调用做出相应的反应。您还需要重写lambda创建,因为它在参数替换中会失败
PS:Never catch基类异常这是一种糟糕的做法,异常时的恐慌返回null是错误的。在@Rafal的宝贵帮助和来自的见解下,我成功地实现了满足我需要的解决方案
public static class EXpressionTreeTools
{
#region ConvertTypesInExpression
/// <summary>
/// Converts the types in the expression.
/// </summary>
/// <typeparam name="TSource">The source type (the "replacee").</typeparam>
/// <typeparam name="TDestin">The destiny type (the replacer).</typeparam>
/// <typeparam name="T">The type of the result fo the expression evaluation</typeparam>
/// <param name="source">The source expression.</param>
/// <returns></returns>
public static Expression<Func<TDestin, T>> ConvertTypesInExpression<TSource, TDestin, T>(Expression<Func<TSource, T>> source)
{
var parameter = Expression.Parameter(typeof(TDestin));
var visitor = new CustomVisitor(parameter);
//Expression<Func<TSource, bool>> expression = x => x.Inner.Name == "ss";
Expression<Func<TDestin, T>> resultExpression = (Expression<Func<TDestin, T>>)visitor.Visit(source);
return resultExpression;
}
#endregion
#region CustomVisitor
/// <summary>
/// A custom "visitor" class to traverse expression trees
/// </summary>
/// <typeparam name="T"></typeparam>
internal class CustomVisitor : ExpressionVisitor
{
private readonly ParameterExpression mParameter;
public CustomVisitor(ParameterExpression parameter)
{
mParameter = parameter;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda(
Visit(node.Body),
node.Parameters.Select(x => (ParameterExpression)Visit(x)).ToArray());
//or simpler but less generic
//return Expression.Lambda(Visit(node.Body), mParameter);
}
//this method will be called twice first for Name and then for Inner
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
//throw new NotImplementedException();
{
Expression exp = this.Visit(node.Expression);
if (exp == null || exp is ConstantExpression) // null=static member
{
object @object = exp == null ? null : ((ConstantExpression)exp).Value;
object value = null; Type type = null;
if (node.Member is FieldInfo)
{
FieldInfo fi = (FieldInfo)node.Member;
value = fi.GetValue(@object);
type = fi.FieldType;
}
else if (node.Member is PropertyInfo)
{
PropertyInfo pi = (PropertyInfo)node.Member;
if (pi.GetIndexParameters().Length != 0)
throw new ArgumentException("cannot eliminate closure references to indexed properties");
value = pi.GetValue(@object, null);
type = pi.PropertyType;
}
return Expression.Constant(value, type);
}
else // otherwise just pass it through
{
return Expression.MakeMemberAccess(exp, node.Member);
}
}
var memberName = node.Member.Name;
var inner = Visit(node.Expression);
var otherMember = inner.Type.GetProperty(memberName);
return Expression.Property(inner, otherMember);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return mParameter;
}
}
#endregion
}
公共静态类EXpressionTreeTools
{
#区域转换类型表达式
///
///转换表达式中的类型。
///
///源类型(“替换项”)。
///命运类型(替换者)。
///表达式计算结果的类型
///源表达式。
///
公共静态表达式ConvertTypesExpression(表达式源)
{
var参数=表达式参数(typeof(TDestin));
var visitor=新CustomVisitor(参数);
//Expression=x=>x.Inner.Name==“ss”;
表达式resultExpression=(表达式)visitor.Visit(源);
返回结果显示;
}
#端区
#地区海关访客
///
///用于遍历表达式树的自定义“访问者”类
///
///
内部类CustomVisitor:ExpressionVisitor
{
私有只读参数expression mpareter;