【问题标题】:The type arguments for method Queryable.Select cannot be inferred from the usage无法从用法中推断方法 Queryable.Select 的类型参数
【发布时间】:2017-05-03 08:41:20
【问题描述】:

我正在使用LambdaExpression 动态选择列:

var property = "power_usage"; // I set this dynamically.
var entityType = typeof(system_state);
var prop = entityType.GetProperty(property);
var source = Expression.Parameter(entityType, "ss");

var func = typeof(Func<,>);
var genericFunc = func.MakeGenericType(typeof(system_state), prop.PropertyType);

var linqQuery = context.system_state
            .Where(ss => ss.time_stamp >= StartDate && ss.time_stamp <= EndDate)
            .Select(genericFunc, Expression.PropertyOrField(source, property), source);

变量genericFunc 应该定义delegateType,但我仍然得到这个错误。我做错了什么?

【问题讨论】:

  • 如果没有完整的具体示例,很难为您提供帮助。 (我建议使用List&lt;T&gt;AsQueryable 来重现这个。)
  • genericFunc、body 和 source 变量中有什么......
  • 不能直接使用Expression.Lambda的非泛型版本。
  • 我已经用更多代码更新了这个问题。 system_state 是使用 Entity Framework 创建的数据库表。
  • 问题是TResult需要在编译时知道,所以linqQueryIQueryable&lt;string&gt;,或者IQueryable&lt;int&gt;等等。这是不可能的在运行时解析var 的类型。可以动态地发出对Select 的调用,但你能得到的只是一个非通用的IQueryable,它不是那么有用。您可以查看 DynamicLINQ 包以了解它如何解决此问题和类似问题。但即使有了它,使用无类型的IQueryable 也很痛苦。

标签: c# linq lambda expression expression-trees


【解决方案1】:

我会引用@Ivan Stoev

问题是TResult需要在编译时知道,所以linqQuery(必须)是IQueryable&lt;string&gt;IQueryable&lt;int&gt;等。在运行时无法解析var的类型。可以动态地发出对Select 的调用,但你能得到的只是一个非通用的IQueryable,这不是那么有用。您可以查看 DynamicLINQ 包以了解它如何解决此问题和类似问题。但即使有了它,使用无类型的IQueryable 也很痛苦。

那么如果你真的想这样做......最后它是你的代码:-)

这可以被缓存:

private static readonly MethodInfo selectT = (from x in typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static)
                                                where x.Name == nameof(Queryable.Select) && x.IsGenericMethod
                                                let gens = x.GetGenericArguments()
                                                where gens.Length == 2
                                                let pars = x.GetParameters()
                                                where pars.Length == 2 &&
                                                    pars[0].ParameterType == typeof(IQueryable<>).MakeGenericType(gens[0]) &&
                                                    pars[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(gens))
                                                select x).Single();

然后:

var property = "power_usage"; // I set this dynamically.
var entityType = typeof(system_state);
var prop = entityType.GetProperty(property);
var source = Expression.Parameter(entityType, "ss");

var func = typeof(Func<,>);
var genericFunc = func.MakeGenericType(typeof(system_state), prop.PropertyType);

var baseQuery = context.system_state
            .Where(ss => ss.time_stamp >= StartDate && ss.time_stamp <= EndDate);

var exp = Expression.Lambda(Expression.Property(source, prop), source);

MethodInfo select = selectT.MakeGenericMethod(entityType, prop.PropertyType);

IQueryable query = (IQueryable)select.Invoke(null, new object[] { baseQuery, exp });

var result = query.Cast<object>().ToArray();

请注意,我正在获取非泛型 IQueryable... 然后我将其元素转换为 object 并执行 ToArray(),但您可以使用它做任何您想做的事情。下面的IQueryable 将是强类型的,因此它将是IQueryable&lt;int&gt;IQueryable&lt;something&gt;,因此您可以将其转换回“真实”接口(@98​​7654337@ 继承自IQueryable

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多