[英]Call Linq GroupBy with IEqualityComparer on dynamic type
I want to create a dynamic GroupBy implementation that ignores case.我想创建一个忽略大小写的动态 GroupBy 实现。 I am using
Expression.Call
, which allows me to pass Expressions as arguments.我正在使用
Expression.Call
,它允许我将表达式作为 arguments 传递。
There are several answers on how to create a custom comparer, but this question is about how to pass a comparer dynamically.关于如何创建自定义比较器有几个答案,但这个问题是关于如何动态传递比较器。
Here is the complete method:这是完整的方法:
public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
if (elementSelector == null) throw new ArgumentNullException("elementSelector");
LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, false, values);
LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, false, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
"GroupBy",
new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
source.Expression,
Expression.Quote(keyLambda),
Expression.Quote(elementLambda)
)
);
}
The call to Queryable.GroupBy
is created by:对
Queryable.GroupBy
的调用由以下人员创建:
Expression.Call(typeof(Queryable), "GroupBy",
new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda))
Queryable.GroupBy
allows to pass a custom IEqualityComparer
. Queryable.GroupBy
允许传递自定义IEqualityComparer
。 How can I do this?我怎样才能做到这一点?
Expression.Call
only allows me to pass arguments of type Expression
. Expression.Call
只允许我传递Expression
类型的 arguments 。
Is there any other way I can group with case ignored, by eg dynamically overriding GetHashCode()
of the keys?有没有其他方法可以忽略大小写,例如动态覆盖键的
GetHashCode()
?
You should call it the same way, as you would normally by adding comparer in GroupBy
call:您应该以相同的方式调用它,就像通常在
GroupBy
调用中添加比较器一样:
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
"GroupBy",
new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
source.Expression,
Expression.Quote(keyLambda),
Expression.Quote(elementLambda),
Expression.Constant(StringComparer.InvariantCultureIgnoreCase)
)
);
StringComparer
can not be used here because the type is dynamic and not string. StringComparer
不能在这里使用,因为类型是动态的而不是字符串。 I had to elaborate on Krzysztofs answer to find a solution that worked.我必须详细说明 Krzysztofs 的答案才能找到有效的解决方案。
First create an instance of a custom dynamic comparer DynamicCaseInsensitiveComparer<T>
(which implements IEqualityComparer) of the same type as keyLambda.Body.Type
.首先创建与
keyLambda.Body.Type
相同类型的自定义动态比较器DynamicCaseInsensitiveComparer<T>
(实现 IEqualityComparer)的实例。 Since the type is provided by a variable, you have to use MakeGenericType
.由于类型是由变量提供的,因此您必须使用
MakeGenericType
。 Then add it in the GroupBy call:然后将其添加到 GroupBy 调用中:
var comparerType = typeof(DynamicCaseInsensitiveComparer<>).MakeGenericType(keyLambda.Body.Type);
var keyComparer = Activator.CreateInstance(comparerType);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
"GroupBy",
new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
source.Expression,
Expression.Quote(keyLambda),
Expression.Quote(elementLambda),
Expression.Constant(keyComparer)
)
);
How to create a custom comparer has been answered in other questions, see for example IEqualityComparer for Annoymous Type如何创建自定义比较器已在其他问题中得到解答,例如IEqualityComparer for Annoymous Type
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.