【问题标题】:How to convert Lambda Expressions from diferent domains?如何转换来自不同域的 Lambda 表达式?
【发布时间】:2018-06-18 14:36:48
【问题描述】:

我正在尝试将 Lambda 表达式从一个域转换为另一个域。 这是我收到的参数:

Expression<Func<Entities.UserRight, bool>> expression

我应该返回一个类型的表达式

Expression<Func<UserRight,bool>> 

UserRight 和 Entities.UserRight 是相同的模型,但属于不同的 nugget 包。

我正在尝试:

public Expression<Func<UserRight,bool>> ConvertExpression(Expression<Func<Entities.UserRight, bool>> expression)
    {
        var resultBody = Expression.Convert(expression.Body, typeof(UserRight));
        var result = Expression.Lambda<Func<UserRight, bool>>(resultBody, expression.Parameters);
        return result;
    }

但我收到 InvalidOperationException 错误

【问题讨论】:

  • 最终您需要将第一个映射到另一个,因为不会进行原生转换。
  • 要做到这一点,你需要从上到下重写表达式树; ExpressionVisitor 是理想的选择,但你不能天真,因为它包含诸如 PropertyInfo / FieldInfo / MethodInfo 标记之类的东西,你需要将它们映射到 other我>类型;这是可能的,但是...
  • 如果您有 UserRight (ur) 和 Entities.UserRight (eur) 类型的变量,您将如何将一个变量转换为另一个变量?
  • @NetMage 也许使用 AutoMapper,为什么?
  • 因为如果你不能简单地从eur 转换为ur 变量,你就不能在表达式树中做到这一点——你需要添加适当的 lambda 框架来准确地处理转换就好像你有变量一样。考虑将 Func&lt;Entities.UserRight, bool&gt; 转换为 Func&lt;UserRight, bool&gt; - 您需要使用转换 lambda ur =&gt; feur(ur.ConvertToEUR()) 包装 feur

标签: c# lambda expression expression-trees linq-expressions


【解决方案1】:

假设我们有两个类 Address1 和 Address2 如下所示:

class Address1
{
    public string City { get; set; }
    public string Detail { get; set; }
}

class Address2
{
    public string City { get; set; }
    public string Detail { get; set; }
}

并且对于 Address1 有这样的表达式:

Expression<Func<Address1, string>> getCityName = ad1 => ad1.City;

我们可以通过 ExpressionVisitor 将表达式更改为可用于 Address2:

public class ExpressionConvertor: ExpressionVisitor
{
    private ParameterExpression ad2Parameter;
    public ExpressionConvertor(ParameterExpression ad2Parameter)
    {
        this.ad2Parameter = ad2Parameter;
    }

    public override Expression Visit(Expression node)
    {
        if(node is LambdaExpression node2)
        {
            var exp = base.Visit(node2.Body);
            return Expression.Lambda(exp, ad2Parameter);
        }
        return base.Visit(node);
    }

    protected override Expression VisitMember(MemberExpression node)
    {       
        if(node.Expression is ParameterExpression)
            return Expression.PropertyOrField(ad2Parameter, node.Member.Name);

        return base.VisitMember(node);
    }
}

最后我们像这样使用这个类:

Expression<Func<Address1, string>> getCityName = ad1 => ad1.City;

var ad2Parameter = Expression.Parameter(typeof(Address2), "ad2");
var convertor = new ExpressionConvertor(ad2Parameter);
var getCityName2 = (Expression<Func<Address2, string>>)convertor.Visit(getCityName);
var getCityName2Method = getCityName2.Compile();

var addr2 = new Address2()
{
    City = "MyCity",
    Detail = "My Address Detail"
};
var cityName = getCityName2Method(addr2);
Console.WriteLine(cityName); //MyCity

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多