如何获取返回要调用的表达式而不是解释为表达式的函数
本文关键字:表达式 解释 函数 调用 何获取 获取 返回 | 更新日期: 2023-09-27 18:15:37
我正在使用SharePoint CSOM。它使用基于表达式的查询语言来指定要检索的数据。我正在研究的系统进行了几个不同的查询,但它们都需要包括某些用于安全检查的数据。例如:
using (ClientContext context = new ClientContext(weburl))
{
var subwebs = context.Web.GetSubwebsForCurrentUser(new SubwebQuery());
context.Load(subwebs,
webs => webs.Include(
// BEGIN security-related boilerplate
web => web.RoleAssignments.Include(
ra => ra.Member,
ra => ra.RoleDefinitionBindings.Include(
rdb => rdb.BasePermissions,
rdb => rdb.RoleTypeKind
)
),
// END security-related boilerplate
web => web.Title,
web => web.ServerRelativeUrl));
context.ExecuteQuery();
}
我试图避免在每个需要的地方复制/粘贴与安全相关的表达式。对Include
方法的检查表明,它接受一个表达式列表作为参数:
IQueryable<TSource> Include<TSource>(
this IQueryable<TSource> clientObjects,
params Expression<Func<TSource, object>>[] retrievals)
where TSource : ClientObject
所以我创建了一个扩展方法,它返回所需的表达式:
public static Expression<Func<T, object>> GetSecurityExpression<T>(this ClientObjectCollection<T> list)
where T : SecurableObject
{
return x => x.RoleAssignments.Include(
ra => ra.Member,
ra => ra.RoleDefinitionBindings.Include(
rdb => rdb.BasePermissions,
rdb => rdb.RoleTypeKind
)
);
}
查询被重写如下:
using (ClientContext context = new ClientContext(weburl))
{
var subwebs = context.Web.GetSubwebsForCurrentUser(new SubwebQuery());
context.Load(subwebs,
webs => webs.Include(
subwebs.GetSecurityExpression(),
web => web.Title,
web => web.ServerRelativeUrl));
context.ExecuteQuery();
}
这个编译得很好,但是在运行时它抛出一个Microsoft.SharePoint.Client.InvalidQueryExpressionException
:
查询表达式"价值(Microsoft.SharePoint.Client.WebCollection) .GetSecurityExpression()"不支持
如果我正确理解异常,编译器不是调用subwebs.GetSecurityExpression()
,而是从它创建一个表达式并将其传递给Include
。
我找到的解决方法是像这样编写调用代码:
using (ClientContext context = new ClientContext(weburl))
{
var subwebs = context.Web.GetSubwebsForCurrentUser(new SubwebQuery());
var securityExpression = subwebs.GetSecurityExpression();
context.Load(subwebs,
webs => webs.Include(
securityExpression,
web => web.Title,
web => web.ServerRelativeUrl));
context.ExecuteQuery();
}
这可以工作,但不像我希望的那样简洁。有没有办法让第一种方法起作用?
你面临的问题是,你的方法GetSecurityExpression将成为第一个变体表达式树的一部分,而SharePoint无法解析这一点。在第二种变体中,在创建表达式树之前对方法调用进行评估,并且实际的表达式树将包含正确的子树(即在GetSecurityExpression方法中编写的内容)。
原则上可以在执行查询之前对表达式树的部分求值。看看ReLinq;它有一个类partialevaluingexpressiontreevisitor来完成这项工作。但是,这将以较小的性能损失为代价。