C# 如何确定表达式是否<;Func<;T、 对象>&燃气轮机;对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

我有一个使用EntityFramework检索实体的方法,该方法接受应包含的导航属性数组:

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;
  }                
}