C# 如何确定表达式是否<;Func<;T、 对象>&燃气轮机;对EntityFramework有效。包括
我有一个使用EntityFramework检索实体的方法,该方法接受应包含的导航属性数组:C# 如何确定表达式是否<;Func<;T、 对象>&燃气轮机;对EntityFramework有效。包括,c#,entity-framework,expression-trees,C#,Entity Framework,Expression Trees,我有一个使用EntityFramework检索实体的方法,该方法接受应包含的导航属性数组: public virtual T GetSingle(Guid id, params Expression<Func<T, object>>[] navigationProperties) { T item = null; IQueryable<T> dbQuery = DBContext.Set<T>(); Expression
public virtual T GetSingle(Guid id, params Expression<Func<T, object>>[] navigationProperties)
{
T item = null;
IQueryable<T> dbQuery = DBContext.Set<T>();
Expression<Func<T, bool>> where = t => t.ID == id;
where = FilterDeleted(where);
//Apply eager loading
if (navigationProperties != null)
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
item = dbQuery
.Where(where)//Apply where clause
.FirstOrDefault();
return item;
}
我几乎没有使用过表达式树,所以我不知道如何开始使用它。我如何分析表达式
以确定它是否包含除这些以外的任何内容,例如.Where
或.OrderBy
或.Take
?好问题:)我试图创建一段适合您需要的代码。使用多个可能的输入对其进行测试;如果它不是为某件事而工作,而有人指出了它,我很乐意为它工作:)
请参阅评论,了解要点
static bool IsValid(LambdaExpression expression)
{
// Expression is in the form of parameter => something
// Body is the 'something' part
var body = expression.Body;
// MemberExpression are like p.Name, that's a valid body
if (body is MemberExpression)
return true;
// MethodCallExpression are like p.Select(...) or p.Where(...) or p.DoSomething(...)
var methodCallExpression = body as MethodCallExpression;
// If it's not a methodcall, it can't be a select, so it's invalid
if (methodCallExpression == null)
return false;
// Method contains the actual MethodInfo
var method = methodCallExpression.Method;
// Select is a generic method, so if it's not generic, it can't be valid
if (!method.IsGenericMethod)
return false;
// Get the actual, parameterless methoddefinition of Enumerable.Select
// NOTE: This is ugly as hell, but AFAIK there's no better way
// just query for the method whose name is 'Select' and has two parameters where the second one has two generic arguments (that's the Func argument)
var selectMethod = typeof(Enumerable).GetMethods()
.Single(m => m.Name == nameof(Enumerable.Select) && m.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2);
// If the method in the methodinfo is not the Select definition, it's not valid
if (method.GetGenericMethodDefinition() != selectMethod)
return false;
// Otherwise the methodcall is in the form of p.Select(p=>'something else')
// innerExpr gets the p=>'something else' part
var innerExpr = methodCallExpression.Arguments[1];
// If the expression really is a lambda expression, then recursively check the p=>'something else' part
if (innerExpr is LambdaExpression lambda)
{
return IsValid(lambda);
}
else
{
// Otherwise it's invalid
// NOTE: this is just in case, I'm not even sure if you can achieve this with regular C# code at compilation time
return false;
}
}
是EF本身使用的方法。我认为这是有效的。我使用了伊万·斯托夫(Ivan Stoev)在你们发布之前评论的一个修改版本。这看起来几乎是一样的,只是有一些小的区别。一个是他们只是使用实际的方法名“Select”来检查调用方法。我想他们的更快,但你的更精确。谢谢你的帮助!
static bool IsValid(LambdaExpression expression)
{
// Expression is in the form of parameter => something
// Body is the 'something' part
var body = expression.Body;
// MemberExpression are like p.Name, that's a valid body
if (body is MemberExpression)
return true;
// MethodCallExpression are like p.Select(...) or p.Where(...) or p.DoSomething(...)
var methodCallExpression = body as MethodCallExpression;
// If it's not a methodcall, it can't be a select, so it's invalid
if (methodCallExpression == null)
return false;
// Method contains the actual MethodInfo
var method = methodCallExpression.Method;
// Select is a generic method, so if it's not generic, it can't be valid
if (!method.IsGenericMethod)
return false;
// Get the actual, parameterless methoddefinition of Enumerable.Select
// NOTE: This is ugly as hell, but AFAIK there's no better way
// just query for the method whose name is 'Select' and has two parameters where the second one has two generic arguments (that's the Func argument)
var selectMethod = typeof(Enumerable).GetMethods()
.Single(m => m.Name == nameof(Enumerable.Select) && m.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2);
// If the method in the methodinfo is not the Select definition, it's not valid
if (method.GetGenericMethodDefinition() != selectMethod)
return false;
// Otherwise the methodcall is in the form of p.Select(p=>'something else')
// innerExpr gets the p=>'something else' part
var innerExpr = methodCallExpression.Arguments[1];
// If the expression really is a lambda expression, then recursively check the p=>'something else' part
if (innerExpr is LambdaExpression lambda)
{
return IsValid(lambda);
}
else
{
// Otherwise it's invalid
// NOTE: this is just in case, I'm not even sure if you can achieve this with regular C# code at compilation time
return false;
}
}