Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将LINQ表达式谓词从一种类型更改为另一种类型_Linq_Entity Framework - Fatal编程技术网

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

将LINQ表达式谓词从一种类型更改为另一种类型,linq,entity-framework,Linq,Entity Framework,我有两门不相关的课。一个作为API公开,另一个由第三方API内部使用 实体是从我们的API公开的,而EntityProvider是从第三方程序集公开的 class Entity { public A { get; set; } } class EntityProvider { public A { get; set; } } 我们API的使用者将提供Expression形式的谓词,我需要将其修改为Expression,以便将其传递给内部第三方程序集。 请帮助进行此转换。由于.NET中

我有两门不相关的课。一个作为API公开,另一个由第三方API内部使用

实体是从我们的API公开的,而EntityProvider是从第三方程序集公开的

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

class EntityProvider
{
  public A { get; set; }
}
我们API的使用者将提供
Expression
形式的谓词,我需要将其修改为
Expression
,以便将其传递给内部第三方程序集。
请帮助进行此转换。

由于.NET中的表达式是不可变的,因此唯一的方法是重新生成整个表达式。要做到这一点,通常需要从类继承。根据您必须转换的表达式的复杂性,这可能相当复杂

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

使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Linq.Expressions;
//要从中转换的类型
公共A类
{
公共int属性1{get;set;}
公共int属性2{get;set;}
}
//要将表达式转换为的类型
公共B级
{
公共int属性1{get;set;}
公共int属性2{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//要转换表达式的表达式
表达式expA=x=>x.Property1==6&&x.Property2==3;
var visitor=新参数类型visitor(expA);
var expB=visitor.Convert();
var b=new b(){Property1=6,Property2=3};
//尝试转换后的表达式
var result=expB.Compile().Invoke(b);
}
}    
公共类参数类型访问者:ExpressionVisitor
{
私有字典转换参数;
私人表达;
公共参数typevisitor(表达式expresionToConvert)
{
//对于原始表达式中的每个参数,将创建一个名称相同但类型已更改的新参数
convertedParameters=expresionToConvert.Parameters
.ToDictionary(
x=>x.Name,
x=>Expression.Parameter(typeof(TTo),x.Name)
);
表达式=expresionToConvert;
}
公共表达式转换()
{
回访(表达)访问(表达);
}
//处理属性和字段访问器
受保护的重写表达式VisitMember(MemberExpression节点)
{
//我们只想替换TFrom类型的节点
//所以我们可以处理形式为x=>x.Property.subperty的表达式
//在表达式x=>x.Property1==6&&x.Property2==3中
//这将替换^^^^^^^^^^^^^^^^^^^^^^^^^^
if(node.Member.DeclaringType==typeof(TFrom))
{
//从类型TTo中获取与类型TFrom的成员匹配的memberinfo
var memeberInfo=typeof(TTo).GetMember(node.Member.Name).First();
//这将实际调用此类中的VisitParameter方法
var newExp=Visit(node.Expression);
返回表达式.MakeMemberAccess(newExp,memeberInfo);
}
其他的
{
返回base.VisitMember(节点);
}
}
//当我们在表达式中引用参数时,将调用此函数
//例如,在表达式x=>x.Property1==6&&x.Property2==3中
//这将被调用两次^^
受保护的重写表达式VisitParameter(ParameterExpression节点)
{            
var newParameter=convertedParameters[node.Name];
返回新参数;
}
//这将是第一个调用的访问方法
//因为我们正在转换LamdaExpressions
受保护的重写表达式VisitLambda(表达式节点)
{
//访问lambda的主体,这将遍历ExpressionTree
//并递归替换表达式中具有匹配访问方法的部分
var newExp=访问(node.Body);
//这将创建新的表达式
Lambda(newExp,convertedParameters.Select(x=>x.Value));
}        
}

由于.NET中的表达式是不可变的,因此唯一的方法是重新生成整个表达式。要做到这一点,通常需要从类继承。根据您必须转换的表达式的复杂性,这可能相当复杂

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

使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Linq.Expressions;
//要从中转换的类型
公共A类
{
公共int属性1{get;set;}
公共int属性2{get;set;}
}
//要将表达式转换为的类型
公共B级
{
公共int属性1{get;set;}
公共int属性2{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//要转换表达式的表达式
表达式expA=x=>x.Property1==6&&x.Property2==3;
var visitor=新参数类型visitor(expA);
var expB=visitor.Convert();
var b=new b(){Property1=6,Property2=3};
//尝试转换后的表达式
var result=expB.Compile().Invoke(b);
}
}    
公共类参数类型访问者:ExpressionVisitor
{
私有字典转换参数;
私人表达;
公共参数typevisitor(表达式expresionToConvert)
{
//对于原始表达式中的每个参数,将创建一个带有th的新参数
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));
    }        
}