我需要一些LINQ扩展的帮助,我很想写。我正在尝试创建一个扩展,计算IQueryable中给定Id的行索引 - 除了该类型可以是任何表。我想我已经完成了大部分工作,但我似乎无法完成它。我在行
上收到以下错误消息Select(lambda)
方法的类型参数 “System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)'无法从用法中推断出来。 尝试指定类型参数 明确。 c:\ users \ shawn_000 \ documents \ visual studio 2013 \ projects \ dexconstruktaweb \ dexconstruktaweb \ generalhelper.cs 157 17 DexConstruktaWeb
private class GetRowCountClass
{
public GetRowCountClass(int id, int index)
{
this.Id = id;
this.Index = index;
}
public int Id { get; set; }
public int Index { get; set; }
}
public static int GetRowCount<T>(this IQueryable<T> query, int id)
{
Type sourceType = typeof(T);
ParameterExpression[] parameter = new ParameterExpression[2];
parameter[0] = Expression.Parameter(sourceType, "x");
parameter[1] = Expression.Parameter(typeof(int), "index");
Type getRowCountType = typeof(GetRowCountClass);
ConstructorInfo constructor = getRowCountType.GetConstructor(new[] { typeof(int), typeof(int)} );
PropertyInfo pi = sourceType.GetProperty("Id");
Expression expr = Expression.Property(parameter[0], pi);
NewExpression member = LambdaExpression.New(constructor,new Expression[] { expr, parameter[1]});
LambdaExpression lambda = Expression.Lambda(member, parameter);
var item = query.AsEnumerable()
.Select(lambda);
}
我知道在选择之后我需要以下行来获取索引返回,但是现在我很难过。任何帮助,将不胜感激。感谢。
.SingleOrDefault(x => x.Id == id).index;
更新
我已经做了一些进一步的挖掘,发现一些LINQ语句不适用于LINQ to Entities,这就是我正在使用的:
http://msdn.microsoft.com/en-us/library/bb738550.aspx
http://msdn.microsoft.com/en-us/library/bb896317.aspx
特别是“LINQ to Entities支持大多数投影和过滤方法的重载,但接受位置参数的除外。”
为了解决这个问题,我使用对AsEnumerable()的调用将其转换为通用的Enumerable,然后调用Select和SingleOrDefault,如上所述。但是,我发现在调用AsEnumerable和ToList之间创建的SQL没有区别,所以我决定简单地调用:
.ToList().FindIndex(e => e.Id == id)
直接在我的IQueryable上创建一个Extension,因为它是一个足够小的代码。
感谢您的帮助。如果有人仍然看到更好的方法,请告诉我。
欢呼声,
更新2
作为一个学习练习,我接受了Servy的建议和这个答案Creating Dynamic Predicates- passing in property to a function as parameter,并提出了以下建议:
public static int GetRowIndex<T>(this IQueryable<T> query, Expression<Func<T, int>> property, int id)
{
var lambda = Expression.Lambda<Predicate<T>>(
Expression.Equal(property.Body, Expression.Constant(id)), property.Parameters);
return query.ToList().FindIndex(lambda.Compile());
}
这可以称为:
var result2 = query.GetRowIndex(x => x.Id, id);
查询的类型为IQueryable。
虽然它没有什么意义,它只是作为一种学习练习才有用。
感谢。
答案 0 :(得分:1)
您的lambda始终返回GetRowCountClass
并使用T
,因此您可以使用Expression.Lambda
方法的通用版本:
var lambda = Expression.Lambda<Func<T, GetRowCountClass>>(member, parameter);
var item = query.Select(lambda);
return item.SingleOrDefault(x => x.Id == id).Index;