Search code examples
c#.netexpression-trees

Expression tree creation with TryParse and Convert C#


I have a list of objects, that I want to filter by an expression which is build at runtime. The final expression contains several conditions, combined with && or ||, wrapped in clauses. Each condition looks like this:

x => x.ValueType == 1 && x.Value == "abc"

As you can see, there are only 2 properties to check. If ValueType is 1, Value is always a string. If ValueType is 2, Value should always contain a string that can be converted to double.

The property Value is of type string. If a condition uses a greater than (>) operator, Value need to be converted to double. So in this case the expression body looks like this:

$x.ValueType == 2 & .Call System.Convert.ToDouble($x.Value) > 5

Until here, everything is working as expected.

The problem:

If I use the expression above (ValueType == 2 && Value > 5) with this list:

var list = new List<Item>();
list.Add(new Item { ValueType = 1, Value = "abc" });
list.Add(new Item { ValueType = 1, Value = "def" });
list.Add(new Item { ValueType = 2, Value = "25" });
list.Add(new Item { ValueType = 2, Value = "37" });
var results = list.AsQueryable().Where(expression);

I get a FormatException: Input string was not in a correct format. I thought he wouldn't try to convert element 1 and 2 to double, because the ValueType condition already returns false. But I was wrong.

Do I need to TryParse all these values before converting them to double, or should I use properties for each value type instead of a single string property? I tried to insert TryParse in the expression tree, but I don't know how...

Changing the object model to multiple properties would cause lots of changes, that's why I want to avoid this "solution".

I am sure, someone in here knows how to handle this problem. Or at least can point me in the right direction.


Solution

  • Use && instead of & for short-circuit evaluation in C#.

    void Main()
    {
        Func<Item, bool> expression = x => x.ValueType == 2 && Convert.ToDouble(x.Value) > 5;
        var list = new List<Item>();
        list.Add(new Item { ValueType = 1, Value = "abc" });
        list.Add(new Item { ValueType = 1, Value = "def" });
        list.Add(new Item { ValueType = 2, Value = "25" });
        list.Add(new Item { ValueType = 2, Value = "37" });
        var results = list.AsQueryable().Where(expression);
    
        results.Dump();
    }
    
    public class Item
    {
        public int ValueType {get;set;}
        public string Value {get;set;}
    }