Dynamic Expression using LINQ. How To Find the Kitchens?

前端 未结 5 1822
难免孤独
难免孤独 2021-01-04 23:29

I try do implement a user dynamic filter, where used selects some properties, selects some operators and selects also the values.

As I didn\'t find yet an answer to

相关标签:
5条回答
  • 2021-01-05 00:11

    I wouldn't build the where clause in that way - I think it's more complex than it needs to be for your needs. Instead, you can combine where clauses like this:

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

    I tested this one, honest :)

    0 讨论(0)
  • 2021-01-05 00:26

    what about this

    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);
    
    0 讨论(0)
  • 2021-01-05 00:28
    var kitchens = from h in houses
                   where h.MainRoom.Type == RoomType.Kitchen
                   select h;
    

    But you must set the RoomType property on the rooms before.

    Ok, edit:

    so you must redefine:

    var comparison = Expression.Lambda<Func<House, bool>>(...
    

    Then, when you use it:

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

    Edit #2:

    Ok, here you go:

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

    Edit #3: Of, for your needs, I am out of ideas for now. I give you one last one:

    Declare an extension method on the String type:

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

    Then use it in that expression like:

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

    That's because apparently enums are treated differently. That extension will leave the string unaltered for other types. Drawback: you have to add another typeof() there.

    0 讨论(0)
  • 2021-01-05 00:29
    // ???????????????????????? DOES NOT WORK
    var kitchens = houses.AsQueryable().Where(comparison);
    

    The Where method takes a Func<House, bool> or a Expression<Func<House, bool>> as the parameter, but the variable comparison is of type LambdaExpression, which doesn't match. You need to use another overload of the method:

    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);
    
    0 讨论(0)
  • 2021-01-05 00:30

    To add a new Enum type to dynamic Linq, you must add the following code :

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

    in predefined types of dynamic. That works for me.

    0 讨论(0)
提交回复
热议问题