簡體   English   中英

C#:組合兩個通用表達式樹

[英]C# : Combine two generic expression trees

我有兩個表達式樹:一個用於獲取類的導航屬性,另一個用於過濾來自此導航屬性的值:我正在嘗試將它們組合起來。

class Program
{
    public interface IDeletable
    {
        bool IsDeleted { get; set; }
    }

    public class User
    {
        public int Id { get; set; }

        public IEnumerable<BlogPost> BlogPosts;
    }

    public class BlogPost : IDeletable
    {
        public string Text { get; set; }
        public bool IsDeleted { get; set; }
    }

    static void Main(string[] args)
    {
        var user = new User()
        {
            Id = 1,
            BlogPosts = new List<BlogPost> {
                new  BlogPost {IsDeleted=false,Text="hello" },
                new  BlogPost {IsDeleted=true,Text="this is deleted" }
             }
        };

        Expression<Func<User, IEnumerable<BlogPost>>> notDeletedExpression = Combine<User, BlogPost>(x => x.BlogPosts, x => !x.IsDeleted);

        Console.ReadLine();
    }

    public static Expression<Func<T, IEnumerable<TChild>>> Combine<T, TChild>
      (
      Expression<Func<T, IEnumerable<TChild>>> navigationProperty,
      Expression<Func<TChild, bool>> filter
      )
      where T : class
      where TChild : class, IDeletable
    {
        //TODO  
        // shourld return x=>x.Posts.Where(p=>IsDeleted==false) ; 
        return null;
    }
}

在下面的示例中,您的示例中的兩個表達式使用Enumerable.Where方法組合:

public static Expression<Func<T, IEnumerable<TChild>>> Combine<T, TChild>
(
  Expression<Func<T, IEnumerable<TChild>>> navigationProperty,
  Expression<Func<TChild, bool>> filter
)
  where T : class
  where TChild : class, IDeletable
{
    // Consider caching the MethodInfo object: 
    var whereMethodInfo = GetEnumerableWhereMethodInfo<TChild>();

    // Produce an Expression tree like:
    // Enumerable.Where(<navigationProperty>, <filter>)
    var filterExpr = Expression
        .Call(
            whereMethodInfo,
            navigationProperty.Body,
            filter
        );

    // Create a Lambda Expression with the parameters
    // used for `navigationProperty` expression
    return Expression
        .Lambda<Func<T, IEnumerable<TChild>>>(
            filterExpr,
            navigationProperty.Parameters
        );
}

private static MethodInfo GetEnumerableWhereMethodInfo<TSource>()
{
    // Get a MethodInfo definition for `Enumerable.Where<>`:
    var methodInfoDefinition = typeof(Enumerable)
       .GetMethods()
       .Where(x => x.Name == nameof(Enumerable.Where))
       .First(x =>
       {
           var parameters = x.GetParameters();

           return
               parameters.Length == 2 &&
               parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
               parameters[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>);
       });

    // Get a MethodInfo object for `Enumerable.Where<TSource>`:
    var methodInfo = methodInfoDefinition.MakeGenericMethod(typeof(TSource));

    return methodInfo;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM