Reputation: 337590
I currently have the following code which allows me to call any method required on the EmailAddress
property of my object, and it works great:
public static Expression<Func<T, bool>> BuildEmailAddressLambda(string method, params object[] args) {
var e = Expression.Parameter(typeof(T), "e");
var propertyInfo = typeof(T).GetProperty("EmailAddress");
var m = Expression.MakeMemberAccess(e, propertyInfo);
var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
var c = args.Select(a => Expression.Constant(a, a.GetType())).ToArray();
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(Expression.Call(m, mi, c), e);
return lambda;
}
// called:
lambda = LambdaExpressionHelper<MailingListMember>.BuildEmailAddressLambda("StartsWith", "r", StringComparison.OrdinalIgnoreCase);
However, I now need to amend the code so that it works for members of my object other than EmailAddress
. Specifically, I would like to create a tree to cover the following expression, where multiple method calls are used:
e.GetStringValue(12).StartsWith("r", StringComparison.OrdinalIgnoreCase);
I have made several attempts, all of which end up in various errors. I feel I am missing something in the logic of how ExpressionTrees are created and some help with this would be greatly appreciated.
Thanks
Upvotes: 5
Views: 2150
Reputation: 6719
Is this good for you?
public static Expression<Func<T, bool>> BuildEmailAddressLambda<T>(
string member, IEnumerable<object> memberArgs, string method, params object[] args)
{
var e = Expression.Parameter(typeof(T), "e");
var memberInfo =
(MemberInfo) typeof(T).GetField(member) ??
(MemberInfo) typeof(T).GetProperty(member) ??
(MemberInfo) typeof(T).GetMethod(member, (memberArgs ?? Enumerable.Empty<object>()).Select(p => p.GetType()).ToArray());
Expression m;
if (memberInfo.MemberType == MemberTypes.Method)
{
var a = memberArgs.Select(p => Expression.Constant(p));
m = Expression.Call(e, (MethodInfo) memberInfo, a);
}
else
{
m = Expression.MakeMemberAccess(e, memberInfo);
}
var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
var c = args.Select(a => Expression.Constant(a, a.GetType()));
return Expression.Lambda<Func<T, bool>>(Expression.Call(m, mi, c), e);
}
// called:
lambda = LambdaExpressionHelper<MailingListMember>.BuildEmailAddressLambda("EmailAddress", null, "StartsWith", "r", StringComparison.OrdinalIgnoreCase);
// or
lambda = LambdaExpressionHelper<MailingListMember>.BuildEmailAddressLambda("GetStringValue", new object[] { 12 }, "StartsWith", "r", StringComparison.OrdinalIgnoreCase);
Upvotes: 4