使用LINQ的动态表达式.如何找到厨房
本文关键字:何找 厨房 表达式 LINQ 动态 使用 | 更新日期: 2023-09-27 18:05:37
我尝试实现一个用户动态过滤器,其中used选择一些属性,选择一些运算符,还选择值。
由于我还没有找到这个问题的答案,我尝试使用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<Room>(new Room[] { aRoom }),
MainRoom = aRoom
};
House yourHouse = new House()
{
Rooms = new List<Room>(new Room[] { bRoom, cRoom }),
MainRoom = bRoom
};
House donaldsHouse = new House()
{
Rooms = new List<Room>(new Room[] { aRoom, bRoom, cRoom }),
MainRoom = aRoom
};
var houses = new List<House>(new House[] { myHouse, yourHouse, donaldsHouse });
//var kitchens = houses.AsQueryable<House>().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<Room> 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<Func<House, bool>>(...
然后,当你使用它时:
var kitchens = houses.AsQueryable().Where(comparison.Compile());
编辑#2:
好的,给你:
var roomTypeParam = Expression.Parameter(typeof(RoomType), "roomType");
// ???????????????????????? DOES NOT WORK
var comparison = Expression.Lambda<Func<House, bool>>(
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))
这是因为显然对遗珠的处理方式不同。对于其他类型,该扩展将保持字符串不变。缺点:您必须在那里添加另一个typeof()
。
// ???????????????????????? DOES NOT WORK
var kitchens = houses.AsQueryable().Where(comparison);
Where
方法采用Func<House, bool>
或Expression<Func<House, bool>>
作为参数,但变量comparison
的类型为LambdaExpression
,这不匹配。你需要使用另一种过载的方法:
var comparison = Expression.Lambda<Func<House, bool>>(
Expression.Equal(houseMainRoomTypeParam,
Expression.Constant("Kitchen", typeof(RoomType))));
//now the type of comparison is Expression<Func<House, bool>>
//the overload in Expression.cs
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters);
我不会用这种方式构建where子句——我认为它比满足您的需要更复杂。相反,您可以组合where子句,如下所示:
var houses = new List<House>(new House[] { myHouse, yourHouse, donaldsHouse });
// A basic predicate which always returns true:
Func<House, bool> 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<House>().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
在预定义类型的动态中。这对我有用。