C# 使用Func<;生成LambdaExpression&燃气轮机;其中returnType为IQueryable<;T>;

C# 使用Func<;生成LambdaExpression&燃气轮机;其中returnType为IQueryable<;T>;,c#,generics,C#,Generics,我正在尝试创建一种基于自己的id获取EntityFramework对象的通用方法,而无需将lambda表达式作为参数传递给方法GetById()。对于下面的代码,实体T的类型为Message,是实现GetById()的类所知道的,并且具有一个属性MessageId,以及几个其他属性。在下面的示例中,MessageId名称已经硬编码,因为这仍然是实验性的-从T中提取id属性名称以后很容易修复 我一直在努力寻找一种方法来构造一个简单的LambdaExpression,它将IQueryable作为参数

我正在尝试创建一种基于自己的id获取EntityFramework对象的通用方法,而无需将lambda表达式作为参数传递给方法
GetById()
。对于下面的代码,实体
T
的类型为
Message
,是实现
GetById()
的类所知道的,并且具有一个属性
MessageId
,以及几个其他属性。在下面的示例中,
MessageId
名称已经硬编码,因为这仍然是实验性的-从
T
中提取id属性名称以后很容易修复

我一直在努力寻找一种方法来构造一个简单的
LambdaExpression
,它将
IQueryable
作为参数类型,并希望有人能知道如何实现这一点。我之所以想要
IQueryable
,是因为我的底层通道工厂提供程序需要它来进行更复杂的查询

下面代码中带有
var exp=Expression.Lambda
的行显示了我希望以其结尾的表达式函数类型定义,但该行给出了异常:

System.Boolean类型的表达式不能用于返回类型IQueryable

这是因为主体具有
Boolean
类型,而我的表达式参数
queryParamtRet
的类型为
IQueryable
。此外,如果我将主体类型更改为
IQueryable
,我将无法找到属性
MessageId
,因为类型不再是
T
类型,而是
IQueryable

public T GetById(int-id)
{
var queryParamLeft=表达式
.参数(typeof(System.Data.Entity.DbSet),“o”);
var queryParamRet=表达式
.参数(类型(IQueryable),“o”);
var entityFrameworkType=表达式
.参数(类型为(T),“o”);
var queryProperty=表达式
.PropertyOrField(entityFrameworkType,“MessageId”);
变量体=表达式
.Equal(queryProperty,Expression.Constant(id));
var exp=表达式
兰姆达先生(
身体,
槲皮素;
var returnXml=DoWithChannel(通道
=>channel.Load(serializer.Serialize(exp));
}

TLDR:写出要为其创建表达式的代码,然后故意创建表达式,从任何内部表达式开始,然后再将其组合到外部表达式中


如果您将预期的代码作为函数编写,它将如下所示

public static IQueryable<T> FilterADbSet(DbSet<T> dbSet)
{
    return Queryable.Where<T>(dbSet, o => o.MessageId == 34);
}
publicstaticiqueryable过滤器数据库集(DbSet-DbSet)
{
返回Queryable.Where(dbSet,o=>o.MessageId==34);
}
它有一个类型为
DbSet
的输入参数,一个类型为
IQueryable
的输出,并使用DbSet变量的参数和表达式调用
Queryable.Where

从外向内工作,首先需要构建表达式以传递给where子句。您已经在代码中这样做了

接下来,需要为where子句创建lambda表达式

var whereClause = Expression.Equal(queryProperty, Expression.Constant(id));

var whereClauseLambda = Expression.Lambda<Func<T, bool>>(whereClause, entityFrameworkType);
var whereClause=Expression.Equal(queryProperty,Expression.Constant(id));
var whereClauseLambda=Expression.Lambda(whereClause,entityFrameworkType);
接下来,如注释所示,您需要使用Expression.Call来创建一个主体

下面是我让代码正常工作的最终结果

static Expression<Func<IQueryable<T>, IQueryable<T>>> WhereMethodExpression = v => v.Where(z => true);
static MethodInfo WhereMethod = ((MethodCallExpression)WhereMethodExpression.Body).Method;

public T GetById(int id)
{
    var queryParamLeft = Expression
        .Parameter(typeof(System.Data.Entity.DbSet<T>), "dbSet");

    var entityFrameworkType = Expression
        .Parameter(typeof(T), "entity");

    var queryProperty = Expression
        .PropertyOrField(entityFrameworkType, "MessageId");

    var whereClause = Expression
        .Equal(queryProperty, Expression.Constant(id));

    var whereClauseLambda = Expression.Lambda<Func<T, bool>>(whereClause, entityFrameworkType);

    var body = Expression.Call(
        WhereMethod,
        queryParamLeft,
        whereClauseLambda
        );

    var exp = Expression
        .Lambda<Func<System.Data.Entity.DbSet<T>, IQueryable<T>>>(
            body,
            queryParamLeft);

    var returnXml = DoWithChannel(channel
                        => channel.Load(serializer.Serialize(exp)));

}
静态表达式WhereMethodExpression=v=>v.Where(z=>true);
静态MethodInfo WhereMethod=((MethodCallExpression)WhereMethodExpression.Body);
公共T GetById(int-id)
{
var queryParamLeft=表达式
.参数(typeof(System.Data.Entity.DbSet),“DbSet”);
var entityFrameworkType=表达式
.参数(类型(T),“实体”);
var queryProperty=表达式
.PropertyOrField(entityFrameworkType,“MessageId”);
var where子句=表达式
.Equal(queryProperty,Expression.Constant(id));
var whereClauseLambda=Expression.Lambda(whereClause,entityFrameworkType);
var body=Expression.Call(
方法,
queryParamLeft,
第14条
);
var exp=表达式
兰姆达先生(
身体,
查询参数(左);
var returnXml=DoWithChannel(通道
=>channel.Load(serializer.Serialize(exp));
}
  • 我使用了一个表达式来获取
    Queryable.Where
  • 您的身体表情需要
    queryParamLeft
    传入。不需要queryParamRet

  • 看起来您的表达式中缺少了一个步骤——如果它是以c#中的LINQ语句编写的,它会是什么样子
    dbSet.Where(o=>o.MessageId==id)
    maybe?您缺少
    Expression.Call(Queryable.Where,Expression.Lambda)
    static Expression<Func<IQueryable<T>, IQueryable<T>>> WhereMethodExpression = v => v.Where(z => true);
    static MethodInfo WhereMethod = ((MethodCallExpression)WhereMethodExpression.Body).Method;
    
    public T GetById(int id)
    {
        var queryParamLeft = Expression
            .Parameter(typeof(System.Data.Entity.DbSet<T>), "dbSet");
    
        var entityFrameworkType = Expression
            .Parameter(typeof(T), "entity");
    
        var queryProperty = Expression
            .PropertyOrField(entityFrameworkType, "MessageId");
    
        var whereClause = Expression
            .Equal(queryProperty, Expression.Constant(id));
    
        var whereClauseLambda = Expression.Lambda<Func<T, bool>>(whereClause, entityFrameworkType);
    
        var body = Expression.Call(
            WhereMethod,
            queryParamLeft,
            whereClauseLambda
            );
    
        var exp = Expression
            .Lambda<Func<System.Data.Entity.DbSet<T>, IQueryable<T>>>(
                body,
                queryParamLeft);
    
        var returnXml = DoWithChannel(channel
                            => channel.Load(serializer.Serialize(exp)));
    
    }