我尝试了对表达式 p => p.Id == 15
进行变异的简单(不完整)实现(代码如下)。有一个名为“CrossMapping”的类定义了原始类型和“新”类型以及类型成员之间的映射。
每个表达式类型都有几种名为 Mutate_XY_Expression
的方法,用于创建新的变异表达式。这些方法需要原始表达式 (MemberExpression originalExpression
) 作为表达式模型、参数表达式列表 (IList<ParameterExpression> parameterExpressions
),这些参数由“父级”表达式定义,并且应该被“父级”的主体所使用,以及定义类型和成员之间映射关系的映射对象 (CrossMapping mapping
)。
对于完整的实现,您可能需要从父级表达式中获取更多信息而不仅仅是参数。但是模式应该是相同的。
示例没有实现访问者模式,因为这样做会增加复杂度。但是转换到访问者模式并不困难。
希望这能有所帮助。
代码(C# 4.0):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
namespace ConsoleApplication1 {
public class Product1 {
public int Id { get; set; }
public string Name { get; set; }
public decimal Weight { get; set; }
}
public class Product2 {
public int Id { get; set; }
public string Name { get; set; }
public decimal Weight { get; set; }
}
class Program {
static void Main( string[] args ) {
var lst1 = new List<Product1> {
new Product1{ Id = 1, Name = "One" },
new Product1{ Id = 15, Name = "Fifteen" },
new Product1{ Id = 9, Name = "Nine" }
};
Expression<Func<Product1, bool>> q1;
q1 = p => p.Id == 15;
var lst2 = new List<Product2> {
new Product2{ Id = 1, Name = "One" },
new Product2{ Id = 15, Name = "Fifteen" },
new Product2{ Id = 9, Name = "Nine" }
};
var tp1 = typeof( Product1 );
var tp1Id = tp1.GetProperty( "Id", BindingFlags.Public | BindingFlags.Instance );
var tp1FuncBool = typeof( Func<,> ).MakeGenericType( tp1, typeof( bool ) );
var tp2 = typeof( Product2 );
var tp21Id = tp2.GetProperty( "Id", BindingFlags.Public | BindingFlags.Instance );
var tp2FuncBool = typeof( Func<,> ).MakeGenericType( tp2, typeof( bool ) );
var cm1 = new CrossMapping {
TypeMapping = {
{ tp1, tp2 },
{ tp1FuncBool, tp2FuncBool }
},
MemberMapping = {
{ tp1Id, tp21Id }
}
};
var cq1_2 = MutateExpression( q1, cm1 );
var dlg1_2 = ((LambdaExpression)cq1_2).Compile();
var rslt1_2 = lst2.Where( (Func<Product2, bool>)dlg1_2 ).ToList();
return;
}
class CrossMapping {
public IDictionary<Type, Type> TypeMapping { get; private set; }
public IDictionary<MemberInfo, MemberInfo> MemberMapping { get; private set; }
public CrossMapping() {
this.TypeMapping = new Dictionary<Type, Type>();
this.MemberMapping = new Dictionary<MemberInfo, MemberInfo>();
}
}
static Expression MutateExpression( Expression originalExpression, CrossMapping mapping ) {
var ret = MutateExpression(
originalExpression: originalExpression,
parameterExpressions: null,
mapping: mapping
);
return ret;
}
static Expression MutateExpression( Expression originalExpression, IList<ParameterExpression> parameterExpressions, CrossMapping mapping ) {
Expression ret;
if ( null == originalExpression ) {
ret = null;
}
else if ( originalExpression is LambdaExpression ) {
ret = MutateLambdaExpression( (LambdaExpression)originalExpression, parameterExpressions, mapping );
}
else if ( originalExpression is BinaryExpression ) {
ret = MutateBinaryExpression( (BinaryExpression)originalExpression, parameterExpressions, mapping );
}
else if ( originalExpression is ParameterExpression ) {
ret = MutateParameterExpression( (ParameterExpression)originalExpression, parameterExpressions, mapping );
}
else if ( originalExpression is MemberExpression ) {
ret = MutateMemberExpression( (MemberExpression)originalExpression, parameterExpressions, mapping );
}
else if ( originalExpression is ConstantExpression ) {
ret = MutateConstantExpression( (ConstantExpression)originalExpression, parameterExpressions, mapping );
}
else {
throw new NotImplementedException();
}
return ret;
}
static Type MutateType( Type originalType, IDictionary<Type, Type> typeMapping ) {
if ( null == originalType ) { return null; }
Type ret;
typeMapping.TryGetValue( originalType, out ret );
if ( null == ret ) { ret = originalType; }
return ret;
}
static MemberInfo MutateMember( MemberInfo originalMember, IDictionary<MemberInfo, MemberInfo> memberMapping ) {
if ( null == originalMember ) { return null; }
MemberInfo ret;
memberMapping.TryGetValue( originalMember, out ret );
if ( null == ret ) { ret = originalMember; }
return ret;
}
static LambdaExpression MutateLambdaExpression( LambdaExpression originalExpression, IList<ParameterExpression> parameterExpressions, CrossMapping mapping ) {
if ( null == originalExpression ) { return null; }
var newParameters = (from p in originalExpression.Parameters
let np = MutateParameterExpression( p, parameterExpressions, mapping )
select np).ToArray();
var newBody = MutateExpression( originalExpression.Body, newParameters, mapping );
var newType = MutateType( originalExpression.Type, mapping.TypeMapping );
var ret = Expression.Lambda(
delegateType: newType,
body: newBody,
name: originalExpression.Name,
tailCall: originalExpression.TailCall,
parameters: newParameters
);
return ret;
}
static BinaryExpression MutateBinaryExpression( BinaryExpression originalExpression, IList<ParameterExpression> parameterExpressions, CrossMapping mapping ) {
if ( null == originalExpression ) { return null; }
var newExprConversion = MutateExpression( originalExpression.Conversion, parameterExpressions, mapping );
var newExprLambdaConversion = (LambdaExpression)newExprConversion;
var newExprLeft = MutateExpression( originalExpression.Left, parameterExpressions, mapping );
var newExprRigth = MutateExpression( originalExpression.Right, parameterExpressions, mapping );
var newType = MutateType( originalExpression.Type, mapping.TypeMapping );
var newMember = MutateMember( originalExpression.Method, mapping.MemberMapping);
var newMethod = (MethodInfo)newMember;
var ret = Expression.MakeBinary(
binaryType: originalExpression.NodeType,
left: newExprLeft,
right: newExprRigth,
liftToNull: originalExpression.IsLiftedToNull,
method: newMethod,
conversion: newExprLambdaConversion
);
return ret;
}
static ParameterExpression MutateParameterExpression( ParameterExpression originalExpresion, IList<ParameterExpression> parameterExpressions, CrossMapping mapping ) {
if ( null == originalExpresion ) { return null; }
ParameterExpression ret = null;
if ( null != parameterExpressions ) {
ret = (from p in parameterExpressions
where p.Name == originalExpresion.Name
select p).FirstOrDefault();
}
if ( null == ret ) {
var newType = MutateType( originalExpresion.Type, mapping.TypeMapping );
ret = Expression.Parameter( newType, originalExpresion.Name );
}
return ret;
}
static MemberExpression MutateMemberExpression( MemberExpression originalExpression, IList<ParameterExpression> parameterExpressions, CrossMapping mapping ) {
if ( null == originalExpression ) { return null; }
var newExpression = MutateExpression( originalExpression.Expression, parameterExpressions, mapping );
var newMember = MutateMember( originalExpression.Member, mapping.MemberMapping );
var ret = Expression.MakeMemberAccess(
expression: newExpression,
member: newMember
);
return ret;
}
static ConstantExpression MutateConstantExpression( ConstantExpression originalExpression, IList<ParameterExpression> parameterExpressions, CrossMapping mapping ) {
if ( null == originalExpression ) { return null; }
var newType = MutateType( originalExpression.Type, mapping.TypeMapping );
var newValue = originalExpression.Value;
var ret = Expression.Constant(
value: newValue,
type: newType
);
return ret;
}
}
}
Expression.Lambda
,该重载(逻辑上)不需要这些参数。 - Jon