为字典创建表达式
本文关键字:表达式 创建 字典 | 更新日期: 2024-09-23 23:50:49
我有一个正在处理的元素。我试着尽可能减少所有内容,因为我觉得它仍然会有很多代码。
public class HtmlElement
{
public IDictionary<string, IEnumerable<string>> Attributes { get; set; }
public IEnumerable<HtmlElement> Descendants { get; set; }
}
我的目标是能够创造这个。我想让它通用化,这样我就可以为"key"answers"value"传递其他值,并执行其他字符串转换/比较。
Expression<Func<HtmlElement, IEnumerable<HtmlElement>>> test =
(HtmlElement ele) =>
ele.Descendants
.Where(d => d.Attributes.Any(a =>
a.Key.Equals("key") &&
a.Value.Any(v => v.Equals("value"))));
这在VS2012的DebugView中显示为:
.Lambda
#Lambda1<System.Func`2[HtmlElement,System.Collections.Generic.IEnumerable`1[HtmlElement]]>(HtmlElement $ele) {
.Call System.Linq.Enumerable.Where(
$ele.Descendants,
.Lambda #Lambda2<System.Func`2[HtmlElement,System.Boolean]>) }
.Lambda
#Lambda2<System.Func`2[HtmlElement,System.Boolean]>(HtmlElement $d) {
.Call System.Linq.Enumerable.Any(
$d.Attributes,
.Lambda #Lambda3<System.Func`2[System.Collections.Generic.KeyValuePair`2[System.String,System.Collections.Generic.IEnumerable`1[System.String]],System.Boolean]>) }
.Lambda
#Lambda3<System.Func`2[System.Collections.Generic.KeyValuePair`2[System.String,System.Collections.Generic.IEnumerable`1[System.String]],System.Boolean]>(System.Collections.Generic.KeyValuePair`2[System.String,System.Collections.Generic.IEnumerable`1[System.String]] $a) {
.Call ($a.Key).Equals("key") && .Call System.Linq.Enumerable.Any(
$a.Value,
.Lambda #Lambda4<System.Func`2[System.String,System.Boolean]>) }
.Lambda
#Lambda4<System.Func`2[System.String,System.Boolean]>(System.String $v) {
.Call $v.Equals("value") }
这是当前失败的呼叫。。。特别是分配给带有错误的anyExpr:
System.Core.dll中出现类型为"System.InvalidOperationException"的异常,但未在用户代码中进行处理其他信息:类型"System.Linq.Enumerable"上没有与提供的类型实参和实参兼容的泛型方法"Any"。如果方法是非泛型的,则不应提供任何类型参数。
var valueBlock = CreateKeyValueBoolExpression("key", "value", "ToLowerInvariant", "Equals","ToLowerInvariant","Equals");
var valueLamda = Expression.Lambda<Func<KeyValuePair<string, IEnumerable<string>>, bool>>(valueBlock, new[] { Expression.Parameter(typeof(KeyValuePair<string, IEnumerable<string>>)) });
var valueType = typeof(HtmlElement);
var valueParam = Expression.Parameter(valueType, "elem");
var valueProp = Expression.Property(valueParam, "Attributes");
var anyExpre = Expression.Call(typeof(Enumerable), EnumerableMethodName.Any.ToString(), new[] { valueType }, valueProp, valueLamda);
以下是上面调用的方法:
public static BinaryExpression CreateKeyValueBoolExpression<TKey, TValue>(TKey keyCompareValue, TValue valueCompareValue, string valueTransform, string valueComparison, string keyTransform, string keyComparison)
{
var keyValueParm = Expression.Parameter(typeof(KeyValuePair<TKey, IEnumerable<TValue>>));
var keyProp = Expression.Property(keyValueParm, "Key");
var keyConst = Expression.Constant(keyCompareValue, typeof(TKey));
var keyBlock = CreateStringCompare(keyTransform, keyComparison, keyProp, keyConst);
var valueType = typeof(TValue);
var valueParam = Expression.Parameter(valueType, "val");
var valueConst = Expression.Constant(valueCompareValue, typeof(TValue));
var valueBlock = CreateStringCompare(valueTransform, valueComparison, valueParam, valueConst);
var valueLamda = Expression.Lambda<Func<TValue, bool>>(valueBlock, new[] { Expression.Parameter(typeof(TValue)) });
var valueProp = Expression.Property(keyValueParm, "Value");
var anyExpre = Expression.Call(typeof(Enumerable), EnumerableMethodName.Any.ToString(), new[] { valueType }, valueProp, valueLamda);
return Expression.AndAlso(keyBlock, anyExpre);
}
public static MethodCallExpression CreateStringCompare(string stringTransform, string stringComparison, Expression memberExpression, ConstantExpression constantExpression)
{
var stringType = typeof(string);
var stringParameter = Expression.Parameter(stringType);
return memberExpression == null
? Expression.Call(
Expression.Call(stringParameter, stringType.GetMethod(stringTransform, Type.EmptyTypes)),
typeof(string).GetMethod(stringComparison, new[] { stringType }),
Expression.Call(constantExpression, stringType.GetMethod(stringTransform, Type.EmptyTypes)))
: Expression.Call(
Expression.Call(memberExpression, stringType.GetMethod(stringTransform, Type.EmptyTypes)),
typeof(string).GetMethod(stringComparison, new[] { stringType }),
Expression.Call(constantExpression, stringType.GetMethod(stringTransform, Type.EmptyTypes)));
}
有了所有这些,调试视图中的Lambda#4和Lambda#3似乎生成得很好,但我一直被Lambda#2卡住了。
如有任何帮助,我们将不胜感激。我在这个项目上投入了很多时间,取得了很多进展,但在这一点上我还是很纠结。
您的序列和lambda都将对Any
的调用中的T
视为KeyValuePair<string, IEnumerable<string>>
。这就是你有一个序列,这就是你的谓词作为参数接受的,但你作为泛型类型参数传递的是HtmlElement
。这是不兼容的,因此出现错误。