xqwzid
xqwzid

Reputation: 520

How do i expand on this expression?

I have this bit of code as an example, basically it spits out

p => p.fieldname.StartsWith("123")

But who would i expand on this to do something like this:

p => p.anotherentity.fieldname.StartsWith("123")

Here is a sample of the code i am have refactored for own needs:

string propertyName = "FirstName";
string methodName = "StartsWith";
string keyword = "123";

Type t = typeof (Person);

ParameterExpression paramExp = Expression.Parameter(t, "p");
// the parameter: p

MemberExpression memberExp = Expression.MakeMemberAccess(paramExp,
                                                         t.GetMember(propertyName).FirstOrDefault());
// part of the body: p.FirstName

MethodCallExpression callExp = Expression.Call(memberExp,
                                               typeof (string).GetMethod(methodName,
                                                                         new Type[] {typeof (string)}),
                                               Expression.Constant(keyword));
// the body: p.FirstName.StartsWith("123")

Expression<Func<Person, bool>> whereExp = Expression.Lambda<Func<Person, bool>>(callExp, paramExp);
Expression<Func<Person, string>> selectExp = Expression.Lambda<Func<Person, string>>(memberExp, paramExp);

Console.WriteLine(whereExp); // p => p.FirstName.StartsWith("123")
Console.WriteLine(selectExp); // p => p.FirstName

To further explain let me show you what i would like to do:

public class Person 
{
    public string IdentityCode {get;set;}
    public Loans Loans {get;set;}
}

public class Loans 
{
  public int Id {get;set;}
  public Asset Assets {get;set;}
  public Person person {get;set;}
}

public class Asset  
{
  public string SerialNumber {get;set;}
}

Then using an expression build something like this:

p => p.Loans.Asset.SerialNumber.StartsWith("123)

Or

p => p.Loans.Person.IdentityCode.StartsWith("123")

Upvotes: 2

Views: 2498

Answers (2)

DarkSquirrel42
DarkSquirrel42

Reputation: 10267

untested, but...

ParameterExpression paramExp = Expression.Parameter(t, "p"); // the parameter: p

MemberExpression memberExp = 
    Expression.MakeMemberAccess(paramExp, t.GetMember(propertyName).FirstOrDefault());

would become something like:

ParameterExpression paramExp = Expression.Parameter(t, "p"); // the parameter: p

MemberExpression otherEntityExp = 
    Expression.MakeMemberAccess(paramExp, t.GetMember("anotherentity").FirstOrDefault());

MemberExpression memberExp = 
    Expression.MakeMemberAccess(otherEntityExp, t.GetMember(propertyName).FirstOrDefault());

Upvotes: 2

Jeff Mercado
Jeff Mercado

Reputation: 134591

I'm not sure what you're asking for, updating an expression or building one from scratch...

If you already have the existing, old expression and want to update it, it would be very easy to create a new one. The idea is to dig through the expression tree down to the expression you want to replace. Then update all parent expressions with the newly replaced one.

Expression<Func<Obj, bool>> expr = p => p.fieldname.StartsWith("123");
var body = expr.Body as MethodCallExpression;   // *.StartsWith()
var obj = body.Object as MemberExpression;      // p.fieldname
var param = expr.Parameters.First();            // p
var newAccess = Expression.PropertyOrField(param, "anotherentity"); // p.anotherentity
var newObj = obj.Update(newAccess);                 // update obj
var newBody = body.Update(newObj, body.Arguments);  // update body
var newExpr = expr.Update(newBody, expr.Parameters);// update expr

Otherwise to build up the expression tree:

Expression<Func<Person, bool>> expr =
    p => p.Loans.Asset.SerialNumber.StartsWith("123");

Work it out from the beginning.

var p = Expression.Parameter(typeof(Person), "p");
var accessLoans = Expression.PropertyOrField(p, "Loans");
var accessAsset = Expression.PropertyOrField(accessLoans, "Asset");
var accessSerialNumber = Expression.PropertyOrField(accessAsset, "SerialNumber");
var callArgs = new Expression[] { Expression.Constant("123", typeof(string)) };
var callStartsWith = Expression.Call(accessSerialNumber, "StartsWith", null, callArgs);
var newExpr = Expression.Lambda<Func<Person, bool>>(callStartsWith, p);

I'll leave the last one as an exercise for you.

Upvotes: 0

Related Questions