使用來自各種SO帖子的信息,特別是這個blog(更正爲使用AndAlso
而不是And
)我已經設法將類似的類型linq表達式組合成一個謂詞。但是現在我想要將兩個表達式結合起來,其中一個是另一個的輸入。這是完全擴展的原始Expression
;組合兩個Linq表達式
private Expression<Func<T, bool>> ExpressionIsNamed(IEnumerable<EntityName> AccessorNames)
{
// works
Expression<Func<T, bool>> Texpr = x => x.Security.Readers.Any(n => AccessorNames.ToStringArray().Contains(n.Text));
return Texpr;
}
注意,重要的是,我需要管理這些爲表達式因爲我的數據庫驅動程序需要走的樹轉換成因此使用編譯(本地通話)結合是不是一種選擇。
所以下面是我想要與上面的Any()
呼叫相結合的功能。最終輸出表達式需要爲Expression<Func<T, bool>>
,我需要將x.Security.Readers
傳遞給這一個。
public static Expression<Func<IEnumerable<EntityName>,bool>> AccessCheckExpression(IEnumerable<EntityName> AccessorNames)
{
return accessList => accessList.Any(n => AccessorNames.ToStringArray().Contains(n.Text));
}
我得儘可能這一點,但我在努力解決如何從accessCheck
換出並讓它在一個表達式中使用accessList
。到目前爲止,我有這個;
private Expression<Func<T, bool>> ExpressionIsNamed(IEnumerable<EntityName> AccessorNames)
{
Expression<Func<T, IEnumerable<EntityName>>> accessList = (T x) => x.Security.Readers;
Expression<Func<IEnumerable<EntityName>, bool>> accessCheck = SecurityDescriptor.AccessCheckExpression(AccessorNames);
// Combine?
Expression<Func<T, bool>> Texpr = ??? accessCheck + accessList ???
return Texpr;
}
[更新]
所以我得遠一點;
class ParameterUpdateVisitor : System.Linq.Expressions.ExpressionVisitor
{
private ParameterExpression _oldParameter;
private ParameterExpression _newParameter;
public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
{
_oldParameter = oldParameter;
_newParameter = newParameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (object.ReferenceEquals(node, _oldParameter))
return _newParameter;
return base.VisitParameter(node);
}
}
static Expression<Func<T, bool>> UpdateParameter<T>(
Expression<Func<T, IEnumerable<EntityName>>> expr,
ParameterExpression newParameter)
{
var visitor = new ParameterUpdateVisitor(expr.Parameters[0], newParameter);
var body = visitor.Visit(expr.Body);
return Expression.Lambda<Func<T, bool>>(body, newParameter);
}
然後我可以編譯;
UpdateParameter(accessList, accessCheck.Parameters[0]);
感謝所有那些Invoke()
建議,但我的猜測是,當他們到了MongoDB的驅動程序的時候也不會像InvocationExpression
。但是,Invoke
和我上面的代碼現在都以完全相同的方式失敗。即;
System.ArgumentException: Expression of type
'System.Func`2[MyLib.Project,System.Collections.Generic.IEnumerable`1[MyLib.EntityName]]'
cannot be used for parameter of type
'System.Collections.Generic.IEnumerable`1[MyLib.EntityName]'
所以這樣看來,隱含參數x.Security.Readers
是一個不同類型的普通老式IEnumerable<EntityName>
您錯過了'ExpressionIsNamed'定義中的類型參數。 –
@HamletHakobyan:不一定。它們的泛型參數可以在包含這個私有方法的類上定義。 –
@DanielHilgarth行。謝謝! –