Moq function call with expression - c#

I have the following Interface that is used to DI and IOC webservice clients
public interface IWcfServiceClientProvider <TContract>: IDisposable where TContract: class
{
TResult Execute<TResult>(Expression<Func<TContract, TResult>> expression);
TResult Execute<TResult>(Expression<Func<TContract, TResult>> expression, bool closeConnection = true);
void Execute(Expression<Action<TContract>> expression);
void Execute(Expression<Action<TContract>> expression, bool closeConnection = true);
}
In my test class I have the following:
List<BaseLookup> myList = new List<BaseLookup> {
new BaseLookup { Id =1, Code = "1001"},
new BaseLookup { Id =2, Code = "1002"},
new BaseLookup { Id =3, Code = "1003"}};
In my test method
Mock<IWcfServiceClientProvider<ILookupService>> lookupServiceClinetProvider = new Mock<IWcfServiceClientProvider<ILookupService>>();
var controller = new ElectorSearchController(lookupServiceClinetProvider.Object);
lookupServiceClinetProvider.Setup(mock => mock.Execute(lookup => lookup.GetList(10))).Returns(myList).Verifiable();
var list = controller.testMethod();
lookupServiceClinetProvider.VerifyAll();
list will only have value when the parameter for GetList is set to 10 i.e GetList(10) Not GetList(i) where i=10
The following works
lookupServiceClinetProvider.Setup(mock => mock.Execute(It.IsAny<Expression<Func<ILookupService, List<BaseLookup>>>>(), true )).Returns((List<BaseLookup>)myList).Verifiable();
But I want to mock the call for GetList and not any call to Execute. If that works, then I can filter the values in the Return method

As an interim solution I wrote a simple brute-force solution to compare expressions following:
public static bool ExpressionMatcher<TIn, TResult>(Expression<Func<TIn, TResult>> expr1, Expression<Func<TIn, TResult>> expr2)
{
if (expr1 == null || expr2 == null)
{
return false;
}
if (expr1 == expr2)
{
return true;
}
if (expr1.Type != expr2.Type)
{
return false;
}
if (expr1.Body == expr2.Body)
{
return true;
}
if (expr1.Body.NodeType != expr2.Body.NodeType)
{
return false;
}
if (expr1.Body.NodeType == ExpressionType.Call)
{
dynamic expr1Body = expr1.Body;
dynamic expr2Body = expr2.Body;
if (expr1Body.Method.Name == expr2Body.Method.Name &&
expr1Body.Method.ReturnType == expr2Body.Method.ReturnType)
{
if (expr1Body.Arguments == null && expr2Body.Arguments == null)
{
return true;
}
if (expr1Body.Arguments.Count != expr2Body.Arguments.Count)
{
return false;
}
return true;
}
}
return false;
}
I used the following to call it
Expression<Func<ILookupService, List<BaseLookup>>> expr = lookup => lookup.GetMyList(It.IsAny<long>());
.Setup(mock => mock.Execute(It.Is<Expression<Func<ILookupService, List<BaseLookup>>>>(method => ExpressionMatcher(method, expr))))
.Returns(myList)
.Verifiable();
I don't need to check the arguments' type at this point. If you have a better answer, please let me know

Related

how to select multi columns filter with lambda expression

is there a short way,
I don't want to use "if state" for every situation
what do you think
Description : type of query is IQueryable
public class OrderFilter{
public string SearchValue { get => _searchValue.ToLower(); set => _searchValue = value; }
public string[] SearchColumns { get; set; }
}
if (!string.IsNullOrWhiteSpace(orderFilter.SearchValue))
if (orderFilter.SearchColumns.Contains("warehouse"))
query = query.Where(x => x.Warehouse.Description.Contains(orderFilter.SearchValue));
if (orderFilter.SearchColumns.Contains("date"))
query = query.Where(x => x.Date.Contains(orderFilter.SearchValue));
if (orderFilter.SearchColumns.Contains("warehouse") && orderFilter.SearchColumns.Contains("date"))
query = query.Where(x => x.OrderNo.Contains(orderFilter.SearchValue)
|| x.Warehouse.Description.Contains(orderFilter.SearchValue)
|| x.Client.Description.Contains(orderFilter.SearchValue)
|| x.Date.ToString().Contains(orderFilter.SearchValue)
|| x.Salesman.Username.Contains(orderFilter.SearchValue)
);
}
Access nested properties with dynamic lambda using Linq.Expression
found the answer I was looking for
public class LambdaHelper
{
public Expression<Func<TSource, bool>> MultiSearchOrder<TSource>(string[] columns, string value)
{
ParameterExpression parameter = Expression.Parameter(typeof(TSource), "x"); // x=> . ... demektir. parametre
MethodInfo containsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
Expression dynamiclambda = null;
MethodCallExpression call = null;
foreach (var propertyName in columns)
{
MemberExpression propertyAccess = NestedExpressionProperty(parameter, propertyName);
call = Expression.Call(propertyAccess, containsMethod, Expression.Constant(value));
if (null == dynamiclambda)
{
dynamiclambda = call;
}
else
{
dynamiclambda = Expression.Or(dynamiclambda, call);
}
}
Expression<Func<TSource, bool>> predicate = Expression.Lambda<Func<TSource, bool>>(dynamiclambda, parameter);
return predicate;
}
private MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
{
string[] parts = propertyName.Split('.');
int partsL = parts.Length;
return (partsL > 1)
?
Expression.Property(
NestedExpressionProperty(
expression,
parts.Take(partsL - 1)
.Aggregate((a, i) => a + "." + i)
),
parts[partsL - 1])
:
Expression.Property(expression, propertyName);
}
I think you add one property (SearchKey) that property contains of all properties value that used for search in writing time and you using this property instead of OR for example :
savingTime: SearhKey="OrderNo.value Warehouse.Description.Value ...."
Searching Time:
if (!string.IsNullOrWhiteSpace(orderFilter.SearchValue))
{
query = query.Where(x =>
x.SearchKey.Contains(orderFilter.SearchValue) );
}
you can do an extension o OrderFilter and reuse it :
public static bool HasAny<TSource>(this OrderFilter filter, IEnumerable<TSource> source)
{
if(filter == null)
throw new ArgumentNullException(nameof(filter));
if(filter.SearchColumns == null)
throw new ArgumentNullException(nameof(filter.SearchColumns));
if(string.IsNullOrWhiteSpace(filter.SearchValue))
throw new ArgumentNullException(nameof(filter.SearchValue));
if(source == null)
throw new ArgumentNullException(nameof(source));
var properties = typeof(TSource).GetProperties().Where(x=> filter.SearchColumns.Any(s=> s.IndexOf(x.Name, StringComparison.InvariantCultureIgnoreCase) > 0));
foreach(var item in source)
{
foreach(var property in properties)
{
var value = property.GetValue(item)?.ToString();
if(value?.Equals(filter.SearchValue , StringComparison.InvariantCultureIgnoreCase) == true)
{
return true;
}
}
}
return false;
}
now you can do this :
var isValueExists = orderFilter.HasAny(query);

How to fetch a model's relationship in a dynamic way?

So I have an application that makes use of a SQLite database. I have some methods for fetching models out of my database. I have a repository that communicaties with my database. And it looks like this:
public class PhotoRepository
{
AppDatabase db = null;
public PhotoRepository ()
{
db = new AppDatabase (Constants.DatabaseFilePath);
}
public Photo GetPhoto(int id)
{
return db.GetItem<Photo>(id);
}
public IEnumerable<Photo> GetPhotos (int album_id)
{
return db.GetItems<Photo>().Where( x => x.Album_Id == album_id );
}
public int SavePhoto (Photo item)
{
return db.SaveItem<Photo>(item);
}
public int DeletePhoto(int id)
{
return db.DeleteItem<Photo>(id);
}
}
I am concerned about the GetPhotos(int album_id) method, because the method it approaches in my database class looks like the following:
public IEnumerable<T> GetItems<T> () where T : BL.Contracts.IBusinessEntity, new ()
{
lock (locker) {
return (from i in Table<T> () select i).ToList ();
}
}
As you can see, it retrieves ALL of the Photo Models from my database and after that I'm, filtering those out that corresponds to the right album_id.
No my question is:
How can I rewrite my method so that it ONLY fetches out the Models corresponding to the album_id. Or even better, how can I rewrite this method to filter any relationship on any property?
So I managed to solve my own answer. Maybe people are interested in the result, so here it comes.
I read a post about dynamic LINQ queries. The post I am talking about can be found here. So the first thing i did was making a Filter class that looks like this:
public class Filter
{
public enum Op
{
Equals,
GreaterThan,
LessThan,
GreaterThanOrEqual,
LessThanOrEqual,
Contains,
StartsWith,
EndsWith
}
public string PropertyName { get ; set ; }
public Op Operation { get ; set ; }
public object Value { get ; set ; }
}
Then I made the ExpressionBuilder class that looks like the following:
public static class ExpressionBuilder
{
private static MethodInfo containsMethod = typeof(string).GetMethod("Contains" );
private static MethodInfo startsWithMethod =
typeof(string).GetMethod("StartsWith", new Type [] {typeof(string)});
private static MethodInfo endsWithMethod =
typeof(string).GetMethod("EndsWith", new Type [] { typeof(string)});
public static Expression<Func<T,
bool >> GetExpression<T>(IList<Filter> filters)
{
if (filters.Count == 0)
return null ;
ParameterExpression param = Expression.Parameter(typeof (T), "t" );
Expression exp = null ;
if (filters.Count == 1)
exp = GetExpression<T>(param, filters[0]);
else if (filters.Count == 2)
exp = GetExpression<T>(param, filters[0], filters[1]);
else
{
while (filters.Count > 0)
{
var f1 = filters[0];
var f2 = filters[1];
if (exp == null )
exp = GetExpression<T>(param, filters[0], filters[1]);
else
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));
filters.Remove(f1);
filters.Remove(f2);
if (filters.Count == 1)
{
exp = Expression .AndAlso(exp, GetExpression<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
return Expression.Lambda<Func<T, bool>>(exp, param);
}
private static Expression GetExpression<T>(ParameterExpression param, Filter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
ConstantExpression constant = Expression.Constant(filter.Value);
switch (filter.Operation)
{
case PhotoWapp.DL.Filter.Op.Equals:
return Expression.Equal(member, constant);
case PhotoWapp.DL.Filter.Op.GreaterThan:
return Expression.GreaterThan(member, constant);
case PhotoWapp.DL.Filter.Op.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, constant);
case PhotoWapp.DL.Filter.Op.LessThan:
return Expression.LessThan(member, constant);
case PhotoWapp.DL.Filter.Op.LessThanOrEqual:
return Expression.LessThanOrEqual(member, constant);
case PhotoWapp.DL.Filter.Op.Contains:
return Expression.Call(member, containsMethod, constant);
case PhotoWapp.DL.Filter.Op.StartsWith:
return Expression.Call(member, startsWithMethod, constant);
case PhotoWapp.DL.Filter.Op.EndsWith:
return Expression.Call(member, endsWithMethod, constant);
}
return null ;
}
private static BinaryExpression GetExpression<T>
(ParameterExpression param, Filter filter1, Filter filter2)
{
Expression bin1 = GetExpression<T>(param, filter1);
Expression bin2 = GetExpression<T>(param, filter2);
return Expression.AndAlso(bin1, bin2);
}
}
Then I added the method GetItems<T>(List<Filter> filters) that looks like the following:
public IEnumerable<T> GetItems<T> (List<Filter> filters) where T : BL.Contracts.IBusinessEntity, new ()
{
lock (locker) {
var deleg = ExpressionBuilder.GetExpression<T> (filters).Compile ();
return (from i in Table<T>().Where(deleg) select i).ToList();
}
}
And to retrieve the records I need, I used the following code.
public IEnumerable<Photo> GetPhotos (int album_id)
{
List<Filter> filters = new List<Filter> () {
new Filter{
PropertyName = "Album_Id",
Operation = Filter.Op.Equals,
Value = album_id
}
};
return db.GetItems<Photo>(filters);
}
Now I can filter nicely on all properties I need! The nice part about this solution is that I can use any class and property to filter on.
I hope this is useful to somebody!

Linq wherein extension methods variable p errors

I write this extensions method for wherein;
public static IQueryable<T> WhereIn<T, TValue>(this IQueryable<T> query,
IEnumerable<TValue> values, params Expression<Func<T, TValue>>[] valueSelectors)
{
return query.Where(BuildContainsExpression(values, valueSelectors));
}
private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(
IEnumerable<TValue> values, params Expression<Func<TElement, TValue>>[] valueSelector)
{
if (null == valueSelector)
{
throw new ArgumentNullException("valueSelector");
}
if (null == values)
{
throw new ArgumentNullException("values");
}
Expression<Func<TElement, bool>> predicate = null;
for (int i = 0; i < valueSelector.Count(); i++)
{
var param = valueSelector[i];
ParameterExpression genericParameter = param.Parameters[0];
TValue[] enumerable = values as TValue[] ?? values.ToArray();
if (!enumerable.Any())
{
return e => false;
}
if (!enumerable.Any())
{
return e => false;
}
IEnumerable<Expression> equals = enumerable.Select(value => (Expression)Expression.Equal(param.Body, Expression.Constant(value, typeof(TValue))));
Expression body = equals.Aggregate(Expression.Or);
Expression<Func<TElement, bool>> partialPredicate = Expression.Lambda<Func<TElement, bool>>(body, genericParameter);
if (predicate == null)
predicate = partialPredicate;
else
{
var orElse = Expression.OrElse(predicate.Body, partialPredicate.Body);
predicate = Expression.Lambda<Func<TElement, bool>>(orElse, genericParameter);
}
}
if (predicate != null)
return predicate;
return null;
}
predicate result is = {p => ((((Convert(p.Id) == 1) Or (Convert(p.Id) == 3)) Or (Convert(p.Id) == 5)) OrElse (((p.MemberId == 1) Or (p.MemberId == 3)) Or (p.MemberId == 5)))}
public class OrderDto { public string Id {get;set;} }
my input is:
var list = new List<int?> {1, 3, 5};
var orderList = Entity.Order.AsQueryable().WhereIn(list, p => p.Id, p => p.MemberId).Select(t => new OrderDto {Id =t.Id}); –
But I get this error;
variable 'p' of type 'OrderDto' referenced from scope '', but it is not defined
How can I fix it?
You are re-using the parameters from the given expressions.
ParameterExpression genericParameter = param.Parameters[0];
When you create new expressions, you also have to create new parameters.
ParameterExpression genericParameter = new ParameterExpression(...);
See here for more information from the master.

Using Expression and Action delegate for decision making structure

I have a instance and I am new to C# delegates , Func , Expression and action . I want to pass a parameter as an expression which would check for few conditions and then it would return or perform based on some conditions provided something like this
var result = Uow.GroupLicense.Set
.Join(Uow.UserGroup.Set, x => x.GroupGuid, y => y.GroupGuid, (GL, G) => new { G, GL })
.Join(Uow.Users.Set, x => x.G.UserGuid, y => y.UserGuid, (UG, U) => new { UG, U })
.SingleOrDefault(x => x.U.UserID == Username);
if (result != null && result.UG.GL.IsActive && result.U.IsEnabled && !result.U.IsLocked)
{
SessionStorage.LoginAttempts = UpdateLoginAttempts(Username, true);
SessionStorage.SessionID = HttpContext.Current.Session.SessionID;
SessionStorage.LoginAttempts = 0;
SessionStorage.UserName = Username;
SessionStorage.ABBUserName = Username;
}
else if (!result.UG.GL.IsActive)
{
result.U.IsEnabled = false;
result.U.IsLocked = true;
Uow.Users.Update(result.U);
Uow.Commit();
ErrorMessage = "User License Expired";
}
else if (result.U.IsLocked)
{
ErrorMessage = "User is locked";
}
else if (!result.U.IsEnabled)
{
ErrorMessage = "User is disabled by administrator";
}
else
{
ErrorMessage = "User doesnt exist ";
}
Now this is my original code . I want to convert this into a decision tree based on two class item conditions . Something like this
if this -> Boolean result = EnsureLicense((x, y) => x.IsEnabled && y.IsActive);
then do Action1
if This -> Boolean result = EnsureLicense((x, y) => !x.IsEnabled && y.IsActive);
then do Action2
if This - > Boolean result = EnsureLicense((x, y) => !x.IsEnabled && y.IsLocked);
then do Action3.
I dont wanna switch it into something like If else structure code with multiple if else and else if structure code . How to proceed with this kind of strategy since I cannot put into switch case .
I want to do it with Actions and Expression and Func delegates . I want to learn how to proceed with this kind of strategy .
Please guide me
Here is solution with actions and Func delegates, which do not use if...else structure. Actually this is a kind of Chain of Responsibility:
public class LicenseHandler
{
private readonly Func<GroupLicense, User, bool> predicate;
private readonly Action action;
private LicenseHandler nextHandler;
public LicenseHandler(Func<GroupLicense,User, bool> predicate, Action action)
{
this.action = action;
this.predicate = predicate;
}
public LicenseHandler SetNext(LicenseHandler handler)
{
nextHandler = handler;
return this;
}
public void Handle(GroupLicense license, User user)
{
if (predicate(license, user))
{
action();
return;
}
if (nextHandler != null)
nextHandler.Handle(license, user);
}
}
Create handlers and chain them:
var handler1 = new LicenseHandler((l, u) => l.IsEnabled && u.IsActive, Action1);
var handler2 = new LicenseHandler((l, u) => !l.IsEnabled && u.IsActive, Action2);
var handler3 = new LicenseHandler((l, u) => !l.IsEnabled && u.IsLocked, Action3);
handler1.SetNext(handler2.SetNext(handler3));
Processing looks like
handler1.Handle(licence, user);
People, who will support delegate-based code instead of simple if-else, accept my deepest sympathy.
UPDATE: If you want nice fluent API, then you can create builder class, which will create handlers chain:
public class LicenseHandlerBuilder
{
private LicenseHandler root;
private LicenseHandler current;
private LicenseHandlerBuilder() { }
public static LicenseHandlerBuilder CreateHandler(
Func<GroupLicense, User, bool> predicate, Action action)
{
var builder = new LicenseHandlerBuilder();
builder.root = new LicenseHandler(predicate, action);
builder.current = builder.root;
return builder;
}
public LicenseHandlerBuilder WithNext(
Func<GroupLicense, User, bool> predicate, Action action)
{
var next = new LicenseHandler(predicate, action);
current.SetNext(next);
current = next;
return this;
}
public LicenseHandler Build()
{
return root;
}
}
Usage:
var handler = LicenseHandlerBuilder
.CreateHandler((l, u) => l.IsEnabled && u.IsActive, Action1)
.WithNext((l, u) => !l.IsEnabled && u.IsActive, Action2)
.WithNext((l, u) => !l.IsEnabled && u.IsLocked, Action3)
.Build();

Combining two lambda expressions in c#

Given a class structure like this:
public class GrandParent
{
public Parent Parent { get; set;}
}
public class Parent
{
public Child Child { get; set;}
}
public class Child
{
public string Name { get; set;}
}
and the following method signature:
Expression<Func<TOuter, TInner>> Combine (Expression<Func<TOuter, TMiddle>>> first, Expression<Func<TMiddle, TInner>> second);
How can I implement said method so that I can call it like this:
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
such that output ends up as:
gp => gp.Parent.Child.Name
Is this possible?
The contents of each Func will only ever be a MemberAccess. I'd rather not end up with output being a nested function call.
Thanks
OK; pretty long snippet, but here's a starter for an expression-rewriter; it doesn't handle a few cases yet (I'll fix it later), but it works for the example given and a lot of others:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
public class GrandParent
{
public Parent Parent { get; set; }
}
public class Parent
{
public Child Child { get; set; }
public string Method(string s) { return s + "abc"; }
}
public class Child
{
public string Name { get; set; }
}
public static class ExpressionUtils
{
public static Expression<Func<T1, T3>> Combine<T1, T2, T3>(
this Expression<Func<T1, T2>> outer, Expression<Func<T2, T3>> inner, bool inline)
{
var invoke = Expression.Invoke(inner, outer.Body);
Expression body = inline ? new ExpressionRewriter().AutoInline(invoke) : invoke;
return Expression.Lambda<Func<T1, T3>>(body, outer.Parameters);
}
}
public class ExpressionRewriter
{
internal Expression AutoInline(InvocationExpression expression)
{
isLocked = true;
if(expression == null) throw new ArgumentNullException("expression");
LambdaExpression lambda = (LambdaExpression)expression.Expression;
ExpressionRewriter childScope = new ExpressionRewriter(this);
var lambdaParams = lambda.Parameters;
var invokeArgs = expression.Arguments;
if (lambdaParams.Count != invokeArgs.Count) throw new InvalidOperationException("Lambda/invoke mismatch");
for(int i = 0 ; i < lambdaParams.Count; i++) {
childScope.Subst(lambdaParams[i], invokeArgs[i]);
}
return childScope.Apply(lambda.Body);
}
public ExpressionRewriter()
{
subst = new Dictionary<Expression, Expression>();
}
private ExpressionRewriter(ExpressionRewriter parent)
{
if (parent == null) throw new ArgumentNullException("parent");
subst = new Dictionary<Expression, Expression>(parent.subst);
inline = parent.inline;
}
private bool isLocked, inline;
private readonly Dictionary<Expression, Expression> subst;
private void CheckLocked() {
if(isLocked) throw new InvalidOperationException(
"You cannot alter the rewriter after Apply has been called");
}
public ExpressionRewriter Subst(Expression from,
Expression to)
{
CheckLocked();
subst.Add(from, to);
return this;
}
public ExpressionRewriter Inline() {
CheckLocked();
inline = true;
return this;
}
public Expression Apply(Expression expression)
{
isLocked = true;
return Walk(expression) ?? expression;
}
private static IEnumerable<Expression> CoalesceTerms(
IEnumerable<Expression> sourceWithNulls, IEnumerable<Expression> replacements)
{
if(sourceWithNulls != null && replacements != null) {
using(var left = sourceWithNulls.GetEnumerator())
using (var right = replacements.GetEnumerator())
{
while (left.MoveNext() && right.MoveNext())
{
yield return left.Current ?? right.Current;
}
}
}
}
private Expression[] Walk(IEnumerable<Expression> expressions) {
if(expressions == null) return null;
return expressions.Select(expr => Walk(expr)).ToArray();
}
private static bool HasValue(Expression[] expressions)
{
return expressions != null && expressions.Any(expr => expr != null);
}
// returns null if no need to rewrite that branch, otherwise
// returns a re-written branch
private Expression Walk(Expression expression)
{
if (expression == null) return null;
Expression tmp;
if (subst.TryGetValue(expression, out tmp)) return tmp;
switch(expression.NodeType) {
case ExpressionType.Constant:
case ExpressionType.Parameter:
{
return expression; // never a need to rewrite if not already matched
}
case ExpressionType.MemberAccess:
{
MemberExpression me = (MemberExpression)expression;
Expression target = Walk(me.Expression);
return target == null ? null : Expression.MakeMemberAccess(target, me.Member);
}
case ExpressionType.Add:
case ExpressionType.Divide:
case ExpressionType.Multiply:
case ExpressionType.Subtract:
case ExpressionType.AddChecked:
case ExpressionType.MultiplyChecked:
case ExpressionType.SubtractChecked:
case ExpressionType.And:
case ExpressionType.Or:
case ExpressionType.ExclusiveOr:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
case ExpressionType.Power:
case ExpressionType.Modulo:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.LeftShift:
case ExpressionType.RightShift:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
{
BinaryExpression binExp = (BinaryExpression)expression;
Expression left = Walk(binExp.Left), right = Walk(binExp.Right);
return (left == null && right == null) ? null : Expression.MakeBinary(
binExp.NodeType, left ?? binExp.Left, right ?? binExp.Right, binExp.IsLiftedToNull,
binExp.Method, binExp.Conversion);
}
case ExpressionType.Not:
case ExpressionType.UnaryPlus:
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.TypeAs:
case ExpressionType.ArrayLength:
{
UnaryExpression unExp = (UnaryExpression)expression;
Expression operand = Walk(unExp.Operand);
return operand == null ? null : Expression.MakeUnary(unExp.NodeType, operand,
unExp.Type, unExp.Method);
}
case ExpressionType.Conditional:
{
ConditionalExpression ce = (ConditionalExpression)expression;
Expression test = Walk(ce.Test), ifTrue = Walk(ce.IfTrue), ifFalse = Walk(ce.IfFalse);
if (test == null && ifTrue == null && ifFalse == null) return null;
return Expression.Condition(test ?? ce.Test, ifTrue ?? ce.IfTrue, ifFalse ?? ce.IfFalse);
}
case ExpressionType.Call:
{
MethodCallExpression mce = (MethodCallExpression)expression;
Expression instance = Walk(mce.Object);
Expression[] args = Walk(mce.Arguments);
if (instance == null && !HasValue(args)) return null;
return Expression.Call(instance, mce.Method, CoalesceTerms(args, mce.Arguments));
}
case ExpressionType.TypeIs:
{
TypeBinaryExpression tbe = (TypeBinaryExpression)expression;
tmp = Walk(tbe.Expression);
return tmp == null ? null : Expression.TypeIs(tmp, tbe.TypeOperand);
}
case ExpressionType.New:
{
NewExpression ne = (NewExpression)expression;
Expression[] args = Walk(ne.Arguments);
if (HasValue(args)) return null;
return ne.Members == null ? Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments))
: Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments), ne.Members);
}
case ExpressionType.ListInit:
{
ListInitExpression lie = (ListInitExpression)expression;
NewExpression ctor = (NewExpression)Walk(lie.NewExpression);
var inits = lie.Initializers.Select(init => new
{
Original = init,
NewArgs = Walk(init.Arguments)
}).ToArray();
if (ctor == null && !inits.Any(init => HasValue(init.NewArgs))) return null;
ElementInit[] initArr = inits.Select(init => Expression.ElementInit(
init.Original.AddMethod, CoalesceTerms(init.NewArgs, init.Original.Arguments))).ToArray();
return Expression.ListInit(ctor ?? lie.NewExpression, initArr);
}
case ExpressionType.NewArrayBounds:
case ExpressionType.NewArrayInit:
/* not quite right... leave as not-implemented for now
{
NewArrayExpression nae = (NewArrayExpression)expression;
Expression[] expr = Walk(nae.Expressions);
if (!HasValue(expr)) return null;
return expression.NodeType == ExpressionType.NewArrayBounds
? Expression.NewArrayBounds(nae.Type, CoalesceTerms(expr, nae.Expressions))
: Expression.NewArrayInit(nae.Type, CoalesceTerms(expr, nae.Expressions));
}*/
case ExpressionType.Invoke:
case ExpressionType.Lambda:
case ExpressionType.MemberInit:
case ExpressionType.Quote:
throw new NotImplementedException("Not implemented: " + expression.NodeType);
default:
throw new NotSupportedException("Not supported: " + expression.NodeType);
}
}
}
static class Program
{
static void Main()
{
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> outputWithInline = myFirst.Combine(mySecond, false);
Expression<Func<GrandParent, string>> outputWithoutInline = myFirst.Combine(mySecond, true);
Expression<Func<GrandParent, string>> call =
ExpressionUtils.Combine<GrandParent, Parent, string>(
gp => gp.Parent, p => p.Method(p.Child.Name), true);
unchecked
{
Expression<Func<double, double>> mathUnchecked =
ExpressionUtils.Combine<double, double, double>(x => (x * x) + x, x => x - (x / x), true);
}
checked
{
Expression<Func<double, double>> mathChecked =
ExpressionUtils.Combine<double, double, double>(x => x - (x * x) , x => (x / x) + x, true);
}
Expression<Func<int,int>> bitwise =
ExpressionUtils.Combine<int, int, int>(x => (x & 0x01) | 0x03, x => x ^ 0xFF, true);
Expression<Func<int, bool>> logical =
ExpressionUtils.Combine<int, bool, bool>(x => x == 123, x => x != false, true);
Expression<Func<int[][], int>> arrayAccess =
ExpressionUtils.Combine<int[][], int[], int>(x => x[0], x => x[0], true);
Expression<Func<string, bool>> isTest =
ExpressionUtils.Combine<string,object,bool>(s=>s, s=> s is Regex, true);
Expression<Func<List<int>>> f = () => new List<int>(new int[] { 1, 1, 1 }.Length);
Expression<Func<string, Regex>> asTest =
ExpressionUtils.Combine<string, object, Regex>(s => s, s => s as Regex, true);
var initTest = ExpressionUtils.Combine<int, int[], List<int>>(i => new[] {i,i,i},
arr => new List<int>(arr.Length), true);
var anonAndListTest = ExpressionUtils.Combine<int, int, List<int>>(
i => new { age = i }.age, i => new List<int> {i, i}, true);
/*
var arrBoundsInit = ExpressionUtils.Combine<int, int[], int[]>(
i => new int[i], arr => new int[arr[0]] , true);
var arrInit = ExpressionUtils.Combine<int, int, int[]>(
i => i, i => new int[1] { i }, true);*/
}
}
I am assuming that your goal is to obtain the expression tree that you would have obtained, had you actually compiled the "combined" lambda. It's much easier to construct a new expression tree that simply invokes the given expression trees appropriately, but I assume that's not what you want.
extract the body of first, cast it to MemberExpression. Call this firstBody.
extract the body of second, call this secondBody
extract the parameter of first. Call this firstParam.
extract the parameter of second. Call this secondParam.
Now, the hard part. Write a visitor pattern implementation which searches through secondBody looking for the single usage of secondParam. (This will be much easier if you know that it's only member access expressions, but you can solve the problem in general.) When you find it, construct a new expression of the same type as its parent, substituting in firstBody for the parameter. Continue to rebuild the transformed tree on the way back out; remember, all you have to rebuild is the "spine" of the tree that contains the parameter reference.
the result of the visitor pass will be a rewritten secondBody with no occurrences of secondParam, only occurences of expressions involving firstParam.
construct a new lambda expression with that body as its body, and firstParam as its param.
and you're done!
Matt Warren's blog might be a good thing for you to read. He designed and implemented all this stuff and has written a lot about ways to rewrite expression trees effectively. (I only did the compiler end of things.)
UPDATE:
As this related answer points out, in .NET 4 there is now a base class for expression rewriters that makes this sort of thing a lot easier.
I'm not sure what you mean by it not being a nested function call, but this will do the trick - with an example:
using System;
using System.IO;
using System.Linq.Expressions;
class Test
{
static Expression<Func<TOuter, TInner>> Combine<TOuter, TMiddle, TInner>
(Expression<Func<TOuter, TMiddle>> first,
Expression<Func<TMiddle, TInner>> second)
{
var parameter = Expression.Parameter(typeof(TOuter), "x");
var firstInvoke = Expression.Invoke(first, new[] { parameter });
var secondInvoke = Expression.Invoke(second, new[] { firstInvoke} );
return Expression.Lambda<Func<TOuter, TInner>>(secondInvoke, parameter);
}
static void Main()
{
Expression<Func<int, string>> first = x => (x + 1).ToString();
Expression<Func<string, StringReader>> second = y => new StringReader(y);
Expression<Func<int, StringReader>> output = Combine(first, second);
Func<int, StringReader> compiled = output.Compile();
var reader = compiled(10);
Console.WriteLine(reader.ReadToEnd());
}
}
I don't know how efficient the generated code will be compared with a single lambda expression, but I suspect it won't be too bad.
For a complete solution have a look at LINQKit:
Expression<Func<GrandParent, string>> output = gp => mySecond.Invoke(myFirst.Invoke(gp));
output = output.Expand().Expand();
output.ToString() prints out
gp => gp.Parent.Child.Name
whereas Jon Skeet's solution yields
x => Invoke(p => p.Child.Name,Invoke(gp => gp.Parent,x))
I guess that's what you're referring to as 'nested function calls'.
Try this:
public static Expression<Func<TOuter, TInner>> Combine<TOuter, TMiddle, TInner>(
Expression<Func<TOuter, TMiddle>> first,
Expression<Func<TMiddle, TInner>> second)
{
return x => second.Compile()(first.Compile()(x));
}
and the usage:
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
var grandParent = new GrandParent
{
Parent = new Parent
{
Child = new Child
{
Name = "child name"
}
}
};
var childName = output.Compile()(grandParent);
Console.WriteLine(childName); // prints "child name"
public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
After a half-day's digging came up with the following solution (much simpler than the accepted answer):
For generic lambda composition:
public static Expression<Func<X, Z>> Compose<X, Y, Z>(Expression<Func<Y, Z>> f, Expression<Func<X, Y>> g)
{
return Expression.Lambda<Func<X, Z>>(Expression.Invoke(f, Expression.Invoke(g, g.Parameters[0])), g.Parameters);
}
This combines two expressions in one, i.e. applies the first expression to the result of the second.
So if we have f(y) and g(x), combine(f,g)(x) === f(g(x))
Transitive and associative, so the combinator can be chained
More specifically, for property access (needed for MVC/EF):
public static Expression<Func<X, Z>> Property<X, Y, Z>(Expression<Func<X, Y>> fObj, Expression<Func<Y, Z>> fProp)
{
return Expression.Lambda<Func<X, Z>>(Expression.Property(fObj.Body, (fProp.Body as MemberExpression).Member as PropertyInfo), fObj.Parameters);
}
Note: fProp must be a simple property access expression, such as x => x.Prop.
fObj can be any expression (but must be MVC-compatible)
With a toolkit called Layer Over LINQ, there's an extension method that does exactly this, combines two expressions to create a new one suitable for use in LINQ to Entities.
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = myFirst.Chain(mySecond);

Categories