我正在尝试构建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`
怎么了?
答案 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);
。看看您的Single
(myEnumerable.Single(o => o.Key == iKey);
)与您的选择表达式(Source
)有何不同?
如果您创建两个表达式作为myEnumerable
调用的参数(一个o => o.Key == iKey
带有Single
输入和输出,一个选择器(source
),它应该解决问题。