使用LINQ进行动态表达。 如何找到厨房?

我尝试实现用户动态filter,其中使用选择一些属性,选择一些运算符并选择值。

由于我没有找到这个问题的答案,我尝试使用LINQ表达式。
主要是我需要确定主要房间是厨房的所有房屋(任何感觉,我知道)。

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; //using System.Linq.Dynamic; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { Room aRoom = new Room() { Name = "a Room" }; Room bRoom = new Room() { Name = "b Room" }; Room cRoom = new Room() { Name = "c Room" }; House myHouse = new House { Rooms = new List(new Room[] { aRoom }), MainRoom = aRoom }; House yourHouse = new House() { Rooms = new List(new Room[] { bRoom, cRoom }), MainRoom = bRoom }; House donaldsHouse = new House() { Rooms = new List(new Room[] { aRoom, bRoom, cRoom }), MainRoom = aRoom }; var houses = new List(new House[] { myHouse, yourHouse, donaldsHouse }); //var kitchens = houses.AsQueryable().Where("MainRoom.Type = RoomType.Kitchen"); //Console.WriteLine("kitchens count = {0}", kitchens.Count()); var houseParam = Expression.Parameter(typeof(House), "house"); var houseMainRoomParam = Expression.Property(houseParam, "MainRoom"); var houseMainRoomTypeParam = Expression.Property(houseMainRoomParam, "Type"); var roomTypeParam = Expression.Parameter(typeof(RoomType), "roomType"); var comparison = Expression.Lambda( Expression.Equal(houseMainRoomTypeParam, Expression.Constant("Kitchen", typeof(RoomType))) ); // ???????????????????????? DOES NOT WORK var kitchens = houses.AsQueryable().Where(comparison); Console.WriteLine("kitchens count = {0}", kitchens.Count()); Console.ReadKey(); } } public class House { public string Address { get; set; } public double Area { get; set; } public Room MainRoom { get; set; } public List Rooms { get; set; } } public class Room { public double Area { get; set; } public string Name { get; set; } public RoomType Type { get; set; } } public enum RoomType { Kitchen, Bedroom, Library, Office } } 

 var kitchens = from h in houses where h.MainRoom.Type == RoomType.Kitchen select h; 

但您必须先在房间中设置RoomType属性。

好的,编辑:

所以你必须重新定义:

 var comparison = Expression.Lambda>(... 

然后,当你使用它时:

 var kitchens = houses.AsQueryable().Where(comparison.Compile()); 

编辑#2:

好的,你走了:

 var roomTypeParam = Expression.Parameter(typeof(RoomType), "roomType"); // ???????????????????????? DOES NOT WORK var comparison = Expression.Lambda>( Expression.Equal(houseMainRoomTypeParam, Expression.Constant(Enum.Parse(typeof(RoomType), "Kitchen"), typeof(RoomType))), houseParam); // ???????????????????????? DOES NOT WORK var kitchens = houses.AsQueryable().Where(comparison); 

编辑#3:对于你的需求,我暂时没有想法。 我给你最后一个:

在String类型上声明一个扩展方法:

 internal static object Prepare(this string value, Type type) { if (type.IsEnum) return Enum.Parse(type, value); return value; } 

然后在表达式中使用它,如:

 Expression.Constant("Kitchen".Prepare(typeof(RoomType)), typeof(RoomType)) 

这是因为显然enum的处理方式不同。 该扩展名将使字符串保持不变为其他类型。 缺点:你必须在那里添加另一个typeof()

 // ???????????????????????? DOES NOT WORK var kitchens = houses.AsQueryable().Where(comparison); 

Where方法采用FuncExpression>作为参数,但变量comparison的类型为LambdaExpression ,不匹配。 您需要使用该方法的另一个重载:

 var comparison = Expression.Lambda>( Expression.Equal(houseMainRoomTypeParam, Expression.Constant("Kitchen", typeof(RoomType)))); //now the type of comparison is Expression> //the overload in Expression.cs public static Expression Lambda(Expression body, params ParameterExpression[] parameters); 

我不会以这种方式构建where子句 – 我认为它比你需要的更复杂。 相反,你可以结合这样的where子句:

 var houses = new List(new House[] { myHouse, yourHouse, donaldsHouse }); // A basic predicate which always returns true: Func housePredicate = h => 1 == 1; // A room name which you got from user input: string userEnteredName = "a Room"; // Add the room name predicate if appropriate: if (!string.IsNullOrWhiteSpace(userEnteredName)) { housePredicate += h => h.MainRoom.Name == userEnteredName; } // A room type which you got from user input: RoomType? userSelectedRoomType = RoomType.Kitchen; // Add the room type predicate if appropriate: if (userSelectedRoomType.HasValue) { housePredicate += h => h.MainRoom.Type == userSelectedRoomType.Value; } // MainRoom.Name = \"a Room\" and Rooms.Count = 3 or // ????????????????????????? var aRoomsHouses = houses.AsQueryable().Where(housePredicate); 

我测试过这个,诚实:)

那这个呢

 var kitchens = houses .SelectMany(h => h.Rooms, (h, r) => new {House = h, Room = r}) .Where(hr => hr.Room.Type == RoomType.Kitchen) .Select(hr => hr.House); 

要向动态Linq添加新的Enum类型,您必须添加以下代码:

 typeof(Enum), typeof(T) T : Enum type 

在预定义的动态类型中。 这对我行得通。