在动态类型上使用 IEqualityComparer 调用 Linq GroupBy
Call Linq GroupBy with IEqualityComparer on dynamic type
我想创建一个忽略大小写的动态 GroupBy 实现。我正在使用 Expression.Call
,它允许我将表达式作为参数传递。
关于如何创建自定义比较器有几个答案,但这个问题是关于如何动态传递比较器的。
完整方法如下:
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)
)
);
}
对 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
允许传递自定义 IEqualityComparer
。我怎样才能做到这一点? Expression.Call
只允许我传递 Expression
.
类型的参数
有没有其他方法可以忽略大小写进行分组,例如动态覆盖键的 GetHashCode()
?
您应该以相同的方式调用它,就像通常在 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
,因为类型是动态的,不是字符串。我必须详细说明 Krzysztofs 的回答才能找到有效的解决方案。
首先创建与 keyLambda.Body.Type
类型相同的自定义动态比较器实例 DynamicCaseInsensitiveComparer<T>
(实现 IEqualityComparer)。由于类型是由变量提供的,因此您必须使用 MakeGenericType
。然后在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 已在其他问题中得到解答,例如参见IEqualityComparer for Annoymous Type
我想创建一个忽略大小写的动态 GroupBy 实现。我正在使用 Expression.Call
,它允许我将表达式作为参数传递。
关于如何创建自定义比较器有几个答案,但这个问题是关于如何动态传递比较器的。
完整方法如下:
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)
)
);
}
对 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
允许传递自定义 IEqualityComparer
。我怎样才能做到这一点? Expression.Call
只允许我传递 Expression
.
有没有其他方法可以忽略大小写进行分组,例如动态覆盖键的 GetHashCode()
?
您应该以相同的方式调用它,就像通常在 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
,因为类型是动态的,不是字符串。我必须详细说明 Krzysztofs 的回答才能找到有效的解决方案。
首先创建与 keyLambda.Body.Type
类型相同的自定义动态比较器实例 DynamicCaseInsensitiveComparer<T>
(实现 IEqualityComparer)。由于类型是由变量提供的,因此您必须使用 MakeGenericType
。然后在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 已在其他问题中得到解答,例如参见IEqualityComparer for Annoymous Type