Linq表达式 - >构建Where(...)。单(...)Linq树表达式

时间:2016-05-19 08:46:15

标签: c# linq linq-expressions

我正在尝试构建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.Collections.Generic.IEnumerable1[Backend.Domain.MetaInfoValue]</code> for the returned value System.Boolean`

的表达式

怎么了?

1 个答案:

答案 0 :(得分:0)

public abstract class RecyclerViewOnScrollListener extends RecyclerView.OnScrollListener { private LinearLayout bottomBarContainer; private boolean animateItems = false; CardStackLayoutManager cardStackLayoutManager; public RecyclerViewOnScrollListener(LinearLayout bottomBarContainer) { this.bottomBarContainer = bottomBarContainer; } public RecyclerViewOnScrollListener(LinearLayout bottomBarContainer, boolean animateItems, CardStackLayoutManager cardStackLayoutManager) { this.bottomBarContainer = bottomBarContainer; this.animateItems = animateItems; this.cardStackLayoutManager = cardStackLayoutManager; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (bottomBarContainer==null || dy==0 ) { return; } long ANIMATION_DURATION = 200L; if (dy>0) { // Scrolling to bottom if (mIsScrollDirectionLocked && mScrollingDirection!=0) return; if (bottomBarContainer.getVisibility()== View.GONE || mIsAnimatingOff) { return; } else { for(int i = 0;i < cardStackLayoutManager.getChildCount();i++) { View view = cardStackLayoutManager.getChildAt(i); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"y",0f,200f); objectAnimator.setDuration(150); objectAnimator.start(); } mScrollingDirection = SCROLLING_DOWN; mIsAnimatingOff = !mIsAnimatingOff; ViewCompat.setTranslationY(bottomBarContainer, 0F); ViewCompat.animate(bottomBarContainer) .translationY(bottomBarContainer.getHeight()) .setDuration(ANIMATION_DURATION) .setListener(new ViewPropertyAnimatorListenerAdapter() { @Override public void onAnimationEnd(View view) { mIsAnimatingOff = !mIsAnimatingOff; bottomBarContainer.setVisibility(View.GONE); } }).start(); } } else { // Scrolling to top if (mIsScrollDirectionLocked && mScrollingDirection!=0) return; if (bottomBarContainer.getVisibility()!=View.VISIBLE && !mIsAnimatingOn) { mScrollingDirection = SCROLLING_UP; mIsAnimatingOn = !mIsAnimatingOn; bottomBarContainer.setVisibility(View.VISIBLE); for(int i = 0;i < cardStackLayoutManager.getChildCount();i++) { View view = cardStackLayoutManager.getChildAt(i); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"y",200f,0f); objectAnimator.setDuration(150); objectAnimator.start(); } ViewCompat.setTranslationY(bottomBarContainer, bottomBarContainer.getHeight()); ViewCompat.animate(bottomBarContainer) .translationY(0F) .setDuration(ANIMATION_DURATION) .setListener(new ViewPropertyAnimatorListenerAdapter() { @Override public void onAnimationEnd(View view) { mIsAnimatingOn = !mIsAnimatingOn; } }).start(); } } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (!mIsScrollDirectionLocked) return; switch (newState) { case RecyclerView.SCROLL_STATE_IDLE: mScrollingDirection = 0; break; default: break; } } private static final int SCROLLING_UP = 1; private static final int SCROLLING_DOWN = 2; private int mScrollingDirection = 0; private boolean mIsScrollDirectionLocked = false; private boolean mIsAnimatingOff = false; private boolean mIsAnimatingOn = false; } 的{​​{1}}似乎就是问题所在。您需要提供(1)Expression.Call和(2)Single。现在,您似乎试图将它们都作为相同的参数(source)。

想一下arguments表达式通常是什么样的:Expression.Lambda<Func<TElementType, bool>>(Expression.Call(whereMethod, collectionMemberExpression, innerCondition), entityParameter);。看看您的SinglemyEnumerable.Single(o => o.Key == iKey);)与您的选择表达式(Source)有何不同?

如果您创建两个表达式作为myEnumerable调用的参数(一个o => o.Key == iKey带有Single输入和输出,一个选择器(source),它应该解决问题。