Mutating the Expression Tree of a Predicate to Target Another Type

Mutating the expression tree of a predicate to target another type

It seems you're generating the parameter expression twice, in VisitMember() here:

var converted = Expression.MakeMemberAccess(
base.Visit(node.Expression),
activeRecordType.GetProperty(node.Member.Name));

...since base.Visit() will end up in VisitParameter I imagine, and in GetMany() itself:

var lambda = Expression.Lambda<Func<ActiveRecord.Widget, bool>>(
visitor.Visit(predicate.Body),
predicate.Parameters.Select(p => visitor.Visit(p));

If you're using a ParameterExpression in the body, it has to be the same instance (not just the same type and name) as the one declared for the Lambda.
I've had problems before with this kind of scenario, though I think the result was that I just wasn't able to create the expression, it would just throw an exception. In any case you might try reusing the parameter instance see if it helps.

Unit test for Expression tree in c#

This shall be simple, though I will use the Expression<Func<SpecFinderDataModel,bool>> instead of LinqKit APIs, which is used internally, In the DoSearch method, you need Expression<Func<SpecFinderDataModel,bool>> as input, based on the method assuming following as the definition of the type SpecFinderDataModel

public class SpecFinderDataModel
{
public string ProductID {get; set;}

public string ISBN13 {get; set;}

public string Title {get; set;}
}

Now you need to simply test various options, as done in regular unit test, a sample:

   // Initial Expression value constant false is the result
Expression<Func<SpecFinderDataModel, bool>> expr = c => false;

// SpecFinderDataModel Object
var sfd = new SpecFinderDataModel
{
ISBN13 = "",
ProductID = "Test A B C",
Title = ""
}

// Call DoSearch and supply the sfd for testing
var result = DoSearch(false,"Test",expr).Compile()(sfd);

// Assert the result in the unit test to understand
Assert.True(result,true);

Like this based on combinations of the DoSearch parameters and test object sfd, you can create any number of unit test cases to test your code

Expression vs Predicate issues

The delegates have different types:

public delegate bool Predicate<T>(T obj);
public delegate TResult Func<T, TResult>(T arg);

The Exists method (and the Find) expect Predicate<T>. The Lambda expression compiles at runtime to Func<T, TResult>.

Try the following:

var existsLambda = Expression.Lambda(typeof(Predicate<string>), 
Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));

You can also use the generic Lambda Function:

var existsLambda = Expression.Lambda<Predicate<string>>(Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));


Related Topics



Leave a reply



Submit