对于通用表达式变量,无法推断类型参数

时间:2017-11-03 19:56:22

标签: c# reflection

我收到以下错误:

the type arguments for method 'Queryable.OrderBy<TSource,TKey>(
    IQueryable<TSource>, Expression<Func<TSource,TKey>>) 
cannot be inferred from the useage.

如何修改Me.GetOrder()myOrderByVariable声明,以便创建一个作为OrderBy() 参数的变量,而不使用自定义扩展方法? 此代码只是一个测试。我需要将变量发送到外部存储库。

void Main()
{
    // Assemble
    string property = "sku";
    var propertyType = Product.GetType().GetProperty(property).GetType();
    var entityType = Product.GetType();

    // Act
    // TODO: begin part to change
    var myOrderByVariable = Me.GetOrder(Product.GetType(), propertyType, property );
    // end part to change

    // Assert
    Product
    .OrderBy( myOrderByVariable )
    .Skip(10).Take(10)
    .Dump();
}

public static class Me
{
    // TODO: begin part to change
    public static Expression<Func<TS, TK>> 
        GetOrder<TS,TK>(TS entity, TK propType, string propertyName)
    {
        //Create x=>x.PropName
        var propertyInfo = typeof(TS).GetProperty(propertyName);
        ParameterExpression arg = Expression.Parameter(typeof(TS), "x");
        MemberExpression property = Expression.Property(arg, propertyName);
        var selector = Expression.Lambda<Func<TS,TK>>(
                       property, new ParameterExpression[] { arg });

        return selector;
    }
    // end part to change
}

其余部分是对问题的回答。

添加编辑1:产品碰巧是使用实体框架从数据库表驱动的POCO:

public partial class Product
{
    public long      sku             { get; set; }
    public string    name            { get; set; }
    public bool      active          { get; set; }
    public int       retailpriceqty  { get; set; }
    public decimal   retailprice     { get; set; }
}

附加编辑2:我如何使用URF Unit of Work & Repositories Framework

中的变量
// in my ASP.NET MVC Controller
// Restful Post instead of Get because query object creates the response
[Route("Product")][HttpPost]
public IEnumerable<ProductVM> GetProductVM(
           [FromBody] QueryObjectVM query )
{
    // QueryObjectVM has a FilterBy string (predicate), OrderBy string,
    // Select string (projection), page size, and page number
    // Select is a TODO until I get dynamic mapping working, which is next

    var queryby = QueryService.CleanupQuery( query);

    var filterby = Spec.FilterBy<Product>( queryby.FilterBy);
    var orderby  = Spec.OrderBy<Product>( queryby.OrderBy);

    // Could possibly inject .OrderBy("sku") via Dynamic Linq,
    // but would repository understand it?
    var result = _productService
        .Query( filterby )
        .OrderBy( o => o.OrderBy( orderby) ) // .OrderBy ( o => o.OrderBy(oo => oo.sku))
        .Select( ProductVM.Map)
        .Skip( (queryby.page - 1) * queryby.pageSize)
        .Take( queryby.pageSize)
        ;
    return result;
}

编辑:这适用于Microsoft Dynamic Linq扩展方法,但我们需要非扩展方法答案。 NetMage在某一点上回答了一个返回object数据类型的方法,该数据类型对于从string等对象派生的变量非常有效,但longint仍然失败。也许使用dynamic代替object作为方法返回类型会起作用吗?可能的?

var result = _Product
             .Query(filter)
             .OrderBy(o => o.OrderBy(s.Count > 0 ? s[0] : "first_field")
                           .OrderBy(s.Count > 1 ? s[1] : "second_field")
                           .OrderBy(s.Count > 2 ? s[2] : "third_field")
                           .OrderBy(s.Count > 3 ? s[3] : "forth_field")
                           .OrderBy(s.Count > 4 ? s[4] : "fifth_field"))
             .SelectPage(ProductVM.Map, query.page, query.pageSize, out count)
;
return result;

1 个答案:

答案 0 :(得分:0)

使用创建整个Expression<Func>表达式lambda的函数替换为OrderBy参数创建OrderBy的函数,然后将其传递给存储库。

在课程Me中,

public static Expression<Func<IQueryable<TS>,IOrderedQueryable<TS>>> MyOrderByLambda<TS>(IQueryable<TS> _, string propertyName) {
    //Create x=>x.PropName
    var argx = Expression.Parameter(typeof(TS), "x");
    var property = Expression.PropertyOrField(argx, propertyName);
    var selector = Expression.Lambda(property, new ParameterExpression[] { argx });

    //Create s=>s.OrderBy<TS, propertyInfo.Type>(x => x.@propertyName)
    var args = Expression.Parameter(typeof(IQueryable<TS>), "s");
    var genericOrderByMI = typeof(Queryable).GetMethods(BindingFlags.Static|BindingFlags.Public).First(mi => mi.Name == "OrderBy" && mi.GetParameters().Length == 2);
    var orderByMI = genericOrderByMI.MakeGenericMethod(typeof(TS), property.Type);
    var orderbybody = Expression.Call(orderByMI, args, selector);
    var orderbyLambda = Expression.Lambda<Func<IQueryable<TS>, IOrderedQueryable<TS>>>(orderbybody, args);
    return orderbyLambda;
}