Linq 表达式 ->构建一个 where(...)。单(...林克树表达式



我正在尝试构建一个像这样的Expression<Func<TEntity, TKey>>

e.Collection.Where(c => c.Key.Equals("key")).Single()

所以,到目前为止,我已经能够构建这样的东西。但是,我还没有弄清楚如何构建Where().Single()链:

Type entityType = typeof(TElementType);
PropertyInfo collectionPropertyInfo = entityType.GetProperty("Metainfos"); // TODO: Pick the property up instead of using a literal string
if (collectionPropertyInfo == null)
    throw new MissingFieldException(string.Format("{0} collection doesn't appear in {1}", "MetaInfos", entityType));
Type collGenericType = collectionPropertyInfo.PropertyType.GetGenericArguments().FirstOrDefault();
if (!collGenericType.IsAssignableFrom(typeof(Domain.MetaInfoValue)))
    throw new TypeLoadException(string.Format("Collection generic type doesn't inherit from {1}", collGenericType));
ParameterExpression entityParameter = Expression.Parameter(entityType, "t");
ParameterExpression metaInfoParameterExpression = Expression.Parameter(collGenericType, "m");
MemberExpression collectionMemberExpression = Expression.Property(entityParameter, collectionPropertyInfo);
MethodInfo whereMethod = typeof(Enumerable).GetMethods().Where(m => m.Name.Equals("Where") && m.GetParameters().Length == 2).First().MakeGenericMethod(collGenericType);
MethodInfo singleMethod = typeof(Enumerable).GetMethods().Where(m => m.Name.Equals("Single") && m.GetParameters().Length == 1).First().MakeGenericMethod(collGenericType);
LambdaExpression innerCondition = Expression.Lambda(
    Expression.GetDelegateType(collGenericType, typeof(bool)),
    Expression.Equal(
        Expression.Property(metaInfoParameterExpression, "Key"),
        Expression.Constant(field)
    ),
    metaInfoParameterExpression
);
return Expression.Lambda<Func<TElementType, TKeyType>>(
    Expression.Call(
        singleMethod,
        Expression.Lambda<Func<TElementType, bool>>(
            Expression.Call(whereMethod, collectionMemberExpression, innerCondition), 
            entityParameter
        )
    )
);}

它抛给我一个ArgumentException

不允许使用 System System.Collections.Generic.IEnumerable1[Backend.Domain.MetaInfoValue]</code> for the returned value 类型的表达式。

怎么了?

似乎Single Expression.Call是问题所在。您需要提供 (1) source和 (2) arguments。 现在,您似乎试图将它们作为相同的参数(Expression.Lambda<Func<TElementType, bool>>(Expression.Call(whereMethod, collectionMemberExpression, innerCondition), entityParameter);)提供。

想想Single表达式通常是什么样子的:myEnumerable.Single(o => o.Key == iKey); 。看看你的SourcemyEnumerable)与你的选择表达式(o => o.Key == iKey)有什么不同?

如果创建两个表达式作为Single调用的参数(一个source具有Enumerable输入和输出,一个选择器(Expression.Lambda<Func<TElementType, bool>>),它应该可以解决问题。