简体   繁体   English

Linq表达式 - >构建一个位置(...)。单个(...)Linq树表达式

[英]Linq Expressions -> Build a Where(…).Single(…) Linq Tree Expression

I'm trying to build an Expression<Func<TEntity, TKey>> like: 我正在尝试构建一个Expression<Func<TEntity, TKey>>如:

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

So, up to now, I've been able to build something like that. 所以,到目前为止,我已经能够构建类似的东西了。 However, I'm not quite to figure out how to build Where().Single() chain: 但是,我不太清楚如何构建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
        )
    )
);}

It throws me an ArgumentException : 它抛出了一个ArgumentException

It's not allowed to use an expression of type System.Collections.Generic.IEnumerable1[Backend.Domain.MetaInfoValue]</code> for the returned value System.Boolean` 不允许使用System.Collections.Generic.IEnumerable1[Backend.Domain.MetaInfoValue]</code> for the returned value类型的表达式System.Collections.Generic.IEnumerable1[Backend.Domain.MetaInfoValue]</code> for the returned value System.Boolean`

What's wrong? 怎么了?

It seems like the Expression.Call for Single is the problem. 似乎Expression.Call for Single就是问题所在。 You need to provide (1) the source and (2) the arguments . 您需要提供(1) source和(2) arguments Right now, you seem to be trying to provide both of them as the same argument ( Expression.Lambda<Func<TElementType, bool>>(Expression.Call(whereMethod, collectionMemberExpression, innerCondition), entityParameter); ). 现在,您似乎试图将它们作为相同的参数提供( Expression.Lambda<Func<TElementType, bool>>(Expression.Call(whereMethod, collectionMemberExpression, innerCondition), entityParameter); )。

Think what a Single expression usually looks like: myEnumerable.Single(o => o.Key == iKey); 想想Single表达式通常是什么样的: myEnumerable.Single(o => o.Key == iKey); . See how your Source ( myEnumerable ) is different than your selection expression ( o => o.Key == iKey )? 看看你的SourcemyEnumerable )与你的选择表达式有什么不同( o => o.Key == iKey )?

If you create two expressions as arguments for your Single call (one source with Enumerable input and output, and one selector ( Expression.Lambda<Func<TElementType, bool>> ), it should solve the issue. 如果您创建两个表达式作为Single调用的参数(一个source使用Enumerable输入和输出,一个选择器( Expression.Lambda<Func<TElementType, bool>> ),它应该解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM