分析此测试:
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;
}
}
请注意,访问成员被呼叫两次,并且必须对两次呼叫做出相应的反应。此外,您还需要重写lambda创建,因为它将在参数替换中失败。
PS:永远不要捕捉基类异常,这是一种糟糕的做法,异常时的恐慌返回null是错误的。