runxc1 / MicroRuleEngine

A .Net Rule Engine for dynamically evaluating business rules compiled on the fly.
MIT License
185 stars 74 forks source link

MRE.ToExpression throws exception #23

Open Vrungar opened 4 years ago

Vrungar commented 4 years ago

I am trying to get the following to work:

var rule = Rule.Create("Description", "Contains", "Do");
var expression = MRE.ToExpression<T>(rule);
var retVal = records.AsQueryable()
                    .Where(expression)
                    .ToList();

where records is a collection of T having a property named Description. When I run the above code MRE.ToExpression<T>(rule) throws an InvalidOperationException with the message: No method 'Contains' on type 'System.String' is compatible with the supplied arguments.' exception.

Also found out that the following will throw the same exception when trying to compile the rule:

var rule = Rule.Create("Description", "Contains", "Do");
var compiledRule = new MRE().CompileRule<T>(rule);
var retVal = records.AsQueryable()
                    .Where(r => compiledRule(r))
                    .ToList();
jamescurran commented 4 years ago

What the rule is actually trying to produce is code similar to :

if(rec.Description.Contains() == "Do")

Which, of course, is not what you want. I may be able to make Contains() a special case to have that work, but in the general case, you need to may the "Do" the "Inputs" property.

Here's the code I used to diagnose this:

[TestMethod]
public void ToExpressionTest()
{
    var records = new HasDescription[] {new HasDescription {Description = "Cat"}, new HasDescription { Description = "Dog" } };

    //var rule = Rule.Create("Description","Create" , "Do");
    var rule = new Rule {MemberName = "Description", Operator = "Contains", Inputs =  new List<object> { "Do" } };
    var expression = MRE.ToExpression<HasDescription>(rule);
    var retVal = records.AsQueryable()
        .Where(expression)
        .ToList();
    Assert.AreEqual(1, retVal.Count);
    Assert.AreEqual("Dog", retVal[0].Description);
}

class HasDescription
{
    public string Description { get; set; }
}