将Lambda表达式转换为表达式树



我有那个lambda:

var Ids = profileExample.CostCenters
           .Where(CostCentre => CostCentre != null)
           .Select(CostCentre => CostCentre.Id);

然后转换为表达式树

    static IEnumerable<Int64> AboveLambdaConvertedToExpressionTree(Profile profileExample)
    {
        //Begin     var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
        var property = profileExample.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != "Id").First();
        var collection = ((IEnumerable)property.GetValue(profileExample, null)).AsQueryable();
        var collectionType = property.PropertyType.GetGenericArguments()[0];
        var collectionTypeName = collectionType.Name;
        var keyType = typeof(Int64);
        var keyName = "Id";
        //BeginWhere
        var parameter = Expression.Parameter(collectionType, collectionTypeName);
        var profileExampleWhere = Expression.Lambda(
                                            Expression.NotEqual(parameter, Expression.Constant(null)),
                                            parameter);
        var profileExampleWhereCall = Expression.Call(typeof(Enumerable),
                                                                "Where",
                                                                new Type[] { collectionType },
                                                                collection.Expression,
                                                                profileExampleWhere);
        //EndWhere
        //BeginSelect
        var profileExampleSelect = Expression.Lambda(Expression.PropertyOrField(parameter, keyName),
                                         parameter);
        var profileExampleSelectCall = Expression.Call(typeof(Enumerable),
                                                  "Select",
                                                  new Type[] { collectionType, keyType },
                                                  profileExampleWhereCall,
                                                  profileExampleSelect);

        var Ids = Expression.Lambda(profileExampleSelectCall).Compile().DynamicInvoke();
        //EndSelect
        //End     var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
        return ((IEnumerable)Ids).Cast<Int64>();
    }

现在我想对bellow lambda

做同样的事情
var result = Set.AsQueryable()
               .Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id)
               .Any(Id => Ids.Contains(Id))).ToList();

但是我卡在.Any(Id => Ids.Contains(Id))....

        var id = Expression.Parameter(typeof(long), "Id");
        var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
        var profile = Expression.Parameter(typeof(Profile), "Profile");
        var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
        var selectCall = Expression.Call(typeof(Enumerable),
                                 "Select",
                                 new Type[] { typeof(CostCentre), typeof(long) }, 
                                 Expression.PropertyOrField(profile, "CostCenters"),
                                 selectLambda);  

如何从selectCall和call id . contains…


作为控制台应用程序运行的完整代码如下:


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressionTrees
{
    class Program
    {
        static void Main(string[] args)
        {
            var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
            Ids = AboveLambdaConvertedToExpressionTree(profileExample);
            var result = Set.AsQueryable().Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();
            //Expression<Func<Profile, bool>> lambda = (Profile) => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id));
            var id = Expression.Parameter(typeof(long), "Id");
            var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
            var profile = Expression.Parameter(typeof(Profile), "Profile");
            var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
            var selectCall = Expression.Call(typeof(Enumerable),
                                     "Select",
                                     new Type[] { typeof(CostCentre), typeof(long) }, 
                                     Expression.PropertyOrField(profile, "CostCenters"),
                                     selectLambda);                                   
        }
        static IEnumerable<Int64> AboveLambdaConvertedToExpressionTree(Profile profileExample)
        {
            // I show that as example of what i need to do
            var keyType = typeof(Int64);
            var keyName = "Id";
            //Begin     var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
            var property = profileExample.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != keyName).First();
            var collection = ((IEnumerable)property.GetValue(profileExample, null)).AsQueryable();
            var collectionType = property.PropertyType.GetGenericArguments()[0];
            var collectionTypeName = collectionType.Name;
            //BeginWhere
            var parameter = Expression.Parameter(collectionType, collectionTypeName);
            var profileExampleWhere = Expression.Lambda(
                                                Expression.NotEqual(parameter, Expression.Constant(null)),
                                                parameter);
            var profileExampleWhereCall = Expression.Call(typeof(Enumerable),
                                                                    "Where",
                                                                    new Type[] { collectionType },
                                                                    collection.Expression,
                                                                    profileExampleWhere);
            //EndWhere
            //BeginSelect
            var profileExampleSelect = Expression.Lambda(Expression.PropertyOrField(parameter, keyName),
                                             parameter);
            var profileExampleSelectCall = Expression.Call(typeof(Enumerable),
                                                      "Select",
                                                      new Type[] { collectionType, keyType },
                                                      profileExampleWhereCall,
                                                      profileExampleSelect);

            var Ids = Expression.Lambda(profileExampleSelectCall).Compile().DynamicInvoke();
            //EndSelect
            //End     var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
            return ((IEnumerable)Ids).Cast<Int64>();
        }
        public partial class Profile
        {
            public virtual Int64 Id { get; set; }
            public virtual ICollection<CostCentre> CostCenters { get; set; }
        }

        public partial class CostCentre
        {
            public virtual Int64 Id { get; set; }
        }
        public static Profile profileExample
        {
            get
            {
                return new Profile()
                {
                    Id = 1,
                    CostCenters = new List<CostCentre>() { new CostCentre() { Id = 2 } }
                };
            }
        }
        public static IList<Profile> Set
        {
            get
            {
                return new List<Profile>() { new Profile() { Id = 1, 
                                                            CostCenters = new List<CostCentre>() {  new CostCentre() { Id = 1 }, 
                                                                                                    new CostCentre() { Id = 2 } } 
                                                          },            
                                            new Profile() { Id = 2, 
                                                            CostCenters = new List<CostCentre>() {  new CostCentre() { Id = 2 }, 
                                                                                                    new CostCentre() { Id = 3 } } 
                                            },
                                            new Profile() { Id = 3, 
                                                            CostCenters = new List<CostCentre>() {  new CostCentre() { Id = 3 } } 
                                            } };
            }
        }
    }
}

由于Any是Generic Method,您需要为特定类型创建它。下面的方法从Enumerable类型得到Any<T>方法。

public static MethodInfo GetAnyExtensionMethod(Type forType)
{
    MethodInfo method = 
        typeof(Enumerable).GetMethods()
                          .First(m => m.Name.Equals("Any") && 
                                      m.GetParameters().Count() == 2);
    return method.MakeGenericMethod(new[] { forType });
}

在MS的帮助下解决了这个问题

class Program
{
    static void Main(string[] args)
    {
        //var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
        var Ids = AboveLambdaConvertedToExpressionTree(profileExample);
        //var result = Set.AsQueryable().Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();
        var id = Expression.Parameter(typeof(long), "Id");
        var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
        var profile = Expression.Parameter(typeof(Profile), "Profile");
        var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
        var selectCall = Expression.Call(typeof(Enumerable),
                                 "Select",
                                 new Type[] { typeof(CostCentre), typeof(long) }, 
                                 Expression.PropertyOrField(profile, "CostCenters"),
                                 selectLambda);                      
        //var id2 = Expression.Parameter(typeof(long), "Id");
        var containsCall = Expression.Call(typeof(Enumerable),
                              "Contains",
                              new Type[] { typeof(long) },
                              Expression.Constant(Ids),
                              id);
        var anyLambda = Expression.Lambda(containsCall, id);
        var anyCall = Expression.Call(typeof(Enumerable),
                     "Any",
                     new Type[] { typeof(long) },
                     selectCall,
                     anyLambda);
        var whereLambda = Expression.Lambda(anyCall, profile);
        var callExpression = Expression.Call(typeof(Queryable),
                                                    "Where",
                                                    new Type[] { typeof(Profile) },
                                                    Set.AsQueryable().Expression,
                                                    whereLambda);

        var result = Expression.Lambda(callExpression).Compile().DynamicInvoke();

    }

相关内容

  • 没有找到相关文章

最新更新