gpt4 book ai didi

linq - 将 LINQ 表达式谓词从一种类型更改为另一种类型

转载 作者:行者123 更新时间:2023-12-05 02:24:14 27 4
gpt4 key购买 nike

我有两个不相关的类(class)。一个作为 API 公开,另一个由第 3 方 API 在内部使用。

实体从我们的 API 公开,而 EntityProvider 来自第 3 方程序集。

class Entity
{
public A { get; set; }
}

class EntityProvider
{
public A { get; set; }
}

我们 API 的使用者将提供 Expression <Func<Entity, bool>> 形式的谓词我需要将其修改为 Expression <Func<EntityProvider, bool>>这样我就可以将其传递给内部第 3 方集会。请帮助进行此转换。

最佳答案

由于 .NET 中的表达式是不可变的,因此唯一的方法是重建整个表达式。为此,通常需要继承 ExpressionVisitor。类(class)。根据您必须转换的表达式的复杂性,这可能会非常复杂。

这是一个访问者的简单示例,它将使用简单的表达式(比如 x=>x.Someproperty == somevalue)。这只是一个让您入门的示例,它绝不会完成或测试(例如,它不会处理表达式中的方法调用)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
//Type from which to convert
public class A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
}

//Type to which we want the Expression converted
public class B
{
public int Property1 { get; set; }
public int Property2 { get; set; }
}

class Program
{
static void Main(string[] args)
{
//the expression we want to convert expresion
Expression<Func<A, bool>> expA = x => x.Property1 == 6 && x.Property2 == 3;

var visitor = new ParameterTypeVisitor<A,B>(expA);
var expB = visitor.Convert();
var b = new B() { Property1 = 6, Property2 = 3 };

//try the converted expression
var result = expB.Compile().Invoke(b);

}
}

public class ParameterTypeVisitor<TFrom,TTo> : ExpressionVisitor
{

private Dictionary<string, ParameterExpression> convertedParameters;
private Expression<Func<TFrom, bool>> expression;

public ParameterTypeVisitor(Expression<Func<TFrom,bool>> expresionToConvert )
{
//for each parameter in the original expression creates a new parameter with the same name but with changed type
convertedParameters = expresionToConvert.Parameters
.ToDictionary(
x => x.Name,
x => Expression.Parameter(typeof (TTo), x.Name)
);

expression = expresionToConvert;
}

public Expression<Func<TTo,bool>> Convert()
{
return (Expression<Func<TTo, bool>>)Visit(expression);
}

//handles Properties and Fields accessors
protected override Expression VisitMember(MemberExpression node)
{
//we want to replace only the nodes of type TFrom
//so we can handle expressions of the form x=> x.Property.SubProperty
//in the expression x=> x.Property1 == 6 && x.Property2 == 3
//this replaces ^^^^^^^^^^^ ^^^^^^^^^^^
if (node.Member.DeclaringType == typeof(TFrom))
{
//gets the memberinfo from type TTo that matches the member of type TFrom
var memeberInfo = typeof (TTo).GetMember(node.Member.Name).First();

//this will actually call the VisitParameter method in this class
var newExp = Visit(node.Expression);
return Expression.MakeMemberAccess(newExp, memeberInfo);
}
else
{
return base.VisitMember(node);
}
}

// this will be called where ever we have a reference to a parameter in the expression
// for ex. in the expression x=> x.Property1 == 6 && x.Property2 == 3
// this will be called twice ^ ^
protected override Expression VisitParameter(ParameterExpression node)
{
var newParameter = convertedParameters[node.Name];
return newParameter;
}

//this will be the first Visit method to be called
//since we're converting LamdaExpressions
protected override Expression VisitLambda<T>(Expression<T> node)
{
//visit the body of the lambda, this will Traverse the ExpressionTree
//and recursively replace parts of the expression we for which we have matching Visit methods
var newExp = Visit(node.Body);

//this will create the new expression
return Expression.Lambda(newExp,convertedParameters.Select(x=>x.Value));
}
}

关于linq - 将 LINQ 表达式谓词从一种类型更改为另一种类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14437239/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com