为字典创建表达式

本文关键字:表达式 创建 字典 | 更新日期: 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。这是不兼容的,因此出现错误。