C# 解析泛型lambda表达式类型

C# 解析泛型lambda表达式类型,c#,linq,entity-framework,C#,Linq,Entity Framework,我有一个调用实体框架函数的方法。它负责发送“select子句”、“orderby子句”和可能的include(考虑到我使用的是延迟加载)。方法如下所示: public IEnumerable<TReturn> GetAll<TReturn, TOrderKey>( Expression<Func<TEntity, TReturn>> selectExp, Expression<Func<TEntity, TOrderKe

我有一个调用实体框架函数的方法。它负责发送“select子句”、“orderby子句”和可能的include(考虑到我使用的是延迟加载)。方法如下所示:

public IEnumerable<TReturn> GetAll<TReturn, TOrderKey>(
    Expression<Func<TEntity, TReturn>> selectExp,
    Expression<Func<TEntity, TOrderKey>> orderbyExp,
    Boolean descending,
    params Expression<Func<TEntity, Object>>[] includeExps)
{
       var query = DbSet.AsQueryable();
       query = !descending ? query.OrderBy(orderByExp) : query.OrderByDescending(orderByExp);
       if (includeExps != null)
          query = includeExps.Aggregate(query, (current, exp) => current.Include(exp));
       return query.Select(selectExp).ToList();
}
public JsonResult GetAllUsers(string sortColumn, bool sortDescending)
    {
        //I don't what is the Type that I should put here
        //It can be anything, like: Expression<Func<User, String>>,
        //Expression<Func<User, Guid>>, Expression<Func<User, Int>>
        ?Type? orderExp;
        switch(sortColumn)
        {
             case "UserId":
                 //Expression<Func<User, Guid>> 
                 orderExp = i => i.UserId; 
                 break;
            case "Name":
                 //Expression<Func<User, String>> 
                 orderExp = i => i.Email; 
                 break;
        }
        //sortColumn string must be translated in a Expression
        var users = _service.GetAll(i => new { i.Name, i.Email }, orderExp, sortDescending, null);
        //
        //
    }
很好用!也就是说,生成的SQL完全符合我的要求

然而,考虑到一个真实的场景(在我的例子中,我使用的是asp.net mvc),我有一个从客户端获取订单参数的操作方法

这就是方法:

public JsonResult GetAllUsers(string sortColumn, bool sortDescending)
{
    //sortColumn string must be translated in a Expression
    var users = _service.GetAll(i => new { i.Name, i.Email }, i => i.Name, sortDescending, null);
    //
    //
}
我的第一次尝试是为每一列创建一个表达式,如下所示:

public IEnumerable<TReturn> GetAll<TReturn, TOrderKey>(
    Expression<Func<TEntity, TReturn>> selectExp,
    Expression<Func<TEntity, TOrderKey>> orderbyExp,
    Boolean descending,
    params Expression<Func<TEntity, Object>>[] includeExps)
{
       var query = DbSet.AsQueryable();
       query = !descending ? query.OrderBy(orderByExp) : query.OrderByDescending(orderByExp);
       if (includeExps != null)
          query = includeExps.Aggregate(query, (current, exp) => current.Include(exp));
       return query.Select(selectExp).ToList();
}
public JsonResult GetAllUsers(string sortColumn, bool sortDescending)
    {
        //I don't what is the Type that I should put here
        //It can be anything, like: Expression<Func<User, String>>,
        //Expression<Func<User, Guid>>, Expression<Func<User, Int>>
        ?Type? orderExp;
        switch(sortColumn)
        {
             case "UserId":
                 //Expression<Func<User, Guid>> 
                 orderExp = i => i.UserId; 
                 break;
            case "Name":
                 //Expression<Func<User, String>> 
                 orderExp = i => i.Email; 
                 break;
        }
        //sortColumn string must be translated in a Expression
        var users = _service.GetAll(i => new { i.Name, i.Email }, orderExp, sortDescending, null);
        //
        //
    }
public JsonResult GetAllUsers(字符串sortColumn,bool sortDescending)
{
//我不知道我应该在这里放什么类型的
//它可以是任何东西,比如:表情,
//表情,表情
?类型?orderExp;
开关(sortColumn)
{
案例“UserId”:
//表情
orderExp=i=>i.UserId;
打破
案例“名称”:
//表情
orderExp=i=>i.电子邮件;
打破
}
//sortColumn字符串必须在表达式中转换
var users=_service.GetAll(i=>new{i.Name,i.Email},orderExp,sortDescending,null);
//
//
}
我想创建一个基于sortProperty的表达式,在stackoverflow中有很多关于它的信息,但是(请参见action方法)必须在进程之前键入变量。不能在每个“case”中调用GetAll方法,因为它返回匿名类型

我无法将所有列转换为
表达式
,因为实体框架不支持它


Linq.Dynamic应该有帮助,但我不想使用字符串参数。

您可以按如下方式重载
GetAll
方法:

public IEnumerable<TReturn> GetAll<TReturn>(
    Expression<Func<TEntity, TReturn>> selectExp,
    string orderColumnName,
    Boolean descending,
    params Expression<Func<TEntity, Object>>[] includeExps)
{
    var entityType = typeof(TEntity);
    var prop = entityType.GetProperty(orderColumnName);
    var param = Expression.Parameter(entityType, "i");
    var orderExp = Expression.Lambda(
        Expression.MakeMemberAccess(param, prop), param);

    // get the original GetAll method overload
    var method = this.GetType().GetMethods().Where(m => m.Name == "GetAll" && m.GetGenericArguments().Length == 2);
    var actualMethod = method.First().MakeGenericMethod(typeof(TReturn), prop.PropertyType);
    return (IEnumerable<TReturn>)actualMethod.Invoke(this, new object[] { selectExp, orderExp, descending, includeExps });
}

您可以按如下方式重载
GetAll
方法:

public IEnumerable<TReturn> GetAll<TReturn>(
    Expression<Func<TEntity, TReturn>> selectExp,
    string orderColumnName,
    Boolean descending,
    params Expression<Func<TEntity, Object>>[] includeExps)
{
    var entityType = typeof(TEntity);
    var prop = entityType.GetProperty(orderColumnName);
    var param = Expression.Parameter(entityType, "i");
    var orderExp = Expression.Lambda(
        Expression.MakeMemberAccess(param, prop), param);

    // get the original GetAll method overload
    var method = this.GetType().GetMethods().Where(m => m.Name == "GetAll" && m.GetGenericArguments().Length == 2);
    var actualMethod = method.First().MakeGenericMethod(typeof(TReturn), prop.PropertyType);
    return (IEnumerable<TReturn>)actualMethod.Invoke(this, new object[] { selectExp, orderExp, descending, includeExps });
}

你的问题是什么?如果你在第一次尝试时不能将你的问题表述为一个问题,那么你将被否决并关闭。对不起。。。我觉得还不够清楚。我想基于属性名创建一个表达式,在stackoverflow中有很多关于它的信息,但是(请参见action方法)必须在进程之前键入变量。GetAll返回一个匿名类型,应该在方法末尾调用。因此您需要一个谓词生成器,除非您希望基于它排序和/或选择数据子集(使用func,而不是谓词)。考虑一下:stackoverflow.com/a/3291811/1144090-告诉我们不能按列号排序,这是我想将列名转换为的。或者,use:)我可以使用Func,但它们没有转换成SQL。Func在数据加载到内存后运行。您可以在此处找到如何按列名排序。严格来说并不是你想要的,但我想至少可以应用于排序。你的问题是到底是什么?如果你在第一次尝试时不能将你的问题表述为一个问题,那么你将被否决并关闭。对不起。。。我觉得还不够清楚。我想基于属性名创建一个表达式,在stackoverflow中有很多关于它的信息,但是(请参见action方法)必须在进程之前键入变量。GetAll返回一个匿名类型,应该在方法末尾调用。因此您需要一个谓词生成器,除非您希望基于它排序和/或选择数据子集(使用func,而不是谓词)。考虑一下:stackoverflow.com/a/3291811/1144090-告诉我们不能按列号排序,这是我想将列名转换为的。或者,use:)我可以使用Func,但它们没有转换成SQL。Func在数据加载到内存后运行。您可以在此处找到如何按列名排序。严格来说并不是你想要的,但我想至少可以应用于排序。你的问题是到底是什么?如果你在第一次尝试时不能将你的问题表述为一个问题,那么你将被否决并关闭。对不起。。。我觉得还不够清楚。我想基于属性名创建一个表达式,在stackoverflow中有很多关于它的信息,但是(请参见action方法)必须在进程之前键入变量。GetAll返回一个匿名类型,应该在方法末尾调用。因此您需要一个谓词生成器,除非您希望基于它排序和/或选择数据子集(使用func,而不是谓词)。考虑一下:stackoverflow.com/a/3291811/1144090-告诉我们不能按列号排序,这是我想将列名转换为的。或者,use:)我可以使用Func,但它们没有转换成SQL。Func在数据加载到内存后运行。您可以在此处找到如何按列名排序。严格来说,这不是你想要的,但我想至少可以应用于排序。