Csharp/C#教程:如何在不同(但兼容)的模型之间转换lambda表达式?分享


如何在不同(但兼容)的模型之间转换lambda表达式?

(基于电子邮件对话,现在记录用于信息共享)我有两个模型用于不同的层:

public class TestDTO { public int CustomerID { get; set; } } //... public class Test { public int CustomerID { get; set; } } 

和我的DTO层的lambda:

 Expression<Func> fc1 = (TestDTO c1) => c1.CustomerID = 10; 

如何将lambda(在一般情况下)转换为讨论其他模型:

 Expression<Func> fc2 = {insert magic here, based on fc1} 

(显然,我们是在相同的测试条件之后,但是使用Test类型)

要做到这一点,你必须完全重建表达式树; 参数将需要重新映射,并且需要重新应用现在与不同类型通信的所有成员访问。 幸运的是, ExpressionVisitor类使得很多内容变得更容易; 例如(在一般情况下完成所有操作,而不仅仅是Func谓词用法):

 class TypeConversionVisitor : ExpressionVisitor { private readonly Dictionary parameterMap; public TypeConversionVisitor( Dictionary parameterMap) { this.parameterMap = parameterMap; } protected override Expression VisitParameter(ParameterExpression node) { // re-map the parameter Expression found; if(!parameterMap.TryGetValue(node, out found)) found = base.VisitParameter(node); return found; } protected override Expression VisitMember(MemberExpression node) { // re-perform any member-binding var expr = Visit(node.Expression); if (expr.Type != node.Type) { MemberInfo newMember = expr.Type.GetMember(node.Member.Name) .Single(); return Expression.MakeMemberAccess(expr, newMember); } return base.VisitMember(node); } } 

在这里,我们传入一个参数字典来重新映射,在VisitParameter应用它。 我们还在VisitMember中检查我们是否已切换类型(如果Visit涉及ParameterExpression或其他MemberExpression ,可能会发生这种情况):如果有,我们将尝试找到另一个同名的成员。

接下来,我们需要一个通用的lambda转换重写器方法:

 // allows extension to other signatures later... private static Expression ConvertImpl(Expression from) where TFrom : class where TTo : class { // figure out which types are different in the function-signature var fromTypes = from.Type.GetGenericArguments(); var toTypes = typeof(TTo).GetGenericArguments(); if (fromTypes.Length != toTypes.Length) throw new NotSupportedException( "Incompatible lambda function-type signatures"); Dictionary typeMap = new Dictionary(); for (int i = 0; i < fromTypes.Length; i++) { if (fromTypes[i] != toTypes[i]) typeMap[fromTypes[i]] = toTypes[i]; } // re-map all parameters that involve different types Dictionary parameterMap = new Dictionary(); ParameterExpression[] newParams = new ParameterExpression[from.Parameters.Count]; for (int i = 0; i < newParams.Length; i++) { Type newType; if(typeMap.TryGetValue(from.Parameters[i].Type, out newType)) { parameterMap[from.Parameters[i]] = newParams[i] = Expression.Parameter(newType, from.Parameters[i].Name); } else { newParams[i] = from.Parameters[i]; } } // rebuild the lambda var body = new TypeConversionVisitor(parameterMap).Visit(from.Body); return Expression.Lambda(body, newParams); } 

这需要一个任意的Expression和一个TTo ,通过以下方式将其转换为Expression

然后,将它们放在一起并公开我们的扩展方法:

 public static class Helpers { public static Expression> Convert( this Expression> from) { return ConvertImpl, Func>(from); } // insert from above: ConvertImpl // insert from above: TypeConversionVisitor } 

et voila; 一个通用的lambda转换例程,具体实现:

 Expression> fc2 = fc1.Convert(); 

您可以使用AutoMapper (无表达式树):

上述就是C#学习教程:如何在不同(但兼容)的模型之间转换lambda表达式?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

 Mapper.CreateMap(); ... Func fc1 = (TestDTO c1) => c1.CustomerID <= 100 && c1.CustomerID >= 10; Func fc2 = (Test t) => fc1(Mapper.Map(t)); 

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1025506.html

(0)
上一篇 2022年1月8日
下一篇 2022年1月8日

精彩推荐