Skip to content

Instantly share code, notes, and snippets.

@bsermons
Created June 17, 2019 15:07
Show Gist options
  • Select an option

  • Save bsermons/664e8f1ee6a83cd360446fef3b3753da to your computer and use it in GitHub Desktop.

Select an option

Save bsermons/664e8f1ee6a83cd360446fef3b3753da to your computer and use it in GitHub Desktop.
public static Expression<Func<IEnumerable<T>, IEnumerable<T>>> Inner<T, F, I>(
this Expression<Func<T, F>> relationship
, Expression<Func<I, bool>> inner
, Func<T, T> cloner)
where F : IEnumerable<I>
{
var relationshipMember = relationship.Body as MemberExpression;
var sourceParam = Expression.Parameter(typeof(IEnumerable<T>), "source");
var selectParam = Expression.Parameter(typeof(T), "selectcParam");
var copyVar = Expression.Variable(typeof(T), "copy");
var parmUpdater = new ParamUpdateVisitor(copyVar);
relationshipMember = (MemberExpression)parmUpdater.Visit(relationshipMember);
//Expression<Func<F, Func<I,bool>, IEnumerable<I>>> where = (s,f) => s.Where(f);
//TODO: make this safer (ie, not `First`)
var whereMethod = typeof(Enumerable).GetMethods().Where(x => x.Name == "Where").First();
whereMethod = whereMethod.MakeGenericMethod(typeof(I));
//var where = Expression.Call(null, whereMethod, selectParam, inner);
var selectBody = Expression.Lambda<Func<T, T>>(
Expression.Block(
new [] { copyVar }
, Expression.Assign(copyVar
, Expression.Call(Expression.Constant(cloner.Target)
, cloner.Method
, selectParam))
, Expression.Assign(relationshipMember
, Expression.Call(null
, whereMethod
, Expression.Invoke(relationship, copyVar)
, inner))
, copyVar)
, selectParam);
//TODO: make this safer
var selectMethod =typeof(Enumerable).GetMethods().Where(x => x.Name == "Select").First();
if (selectMethod == null) throw new Exception("Select method not found");
selectMethod = selectMethod.MakeGenericMethod(typeof(T), typeof(T));
var select = Expression.Call(null, selectMethod, sourceParam, selectBody);
// Expression<Func<IEnumerable<T>, Func<T,T>, IEnumerable<T>>> selectMethod = (s,f) => s.Select(f);
// var select = Expression.Invoke(selectMethod, sourceParam, selectBody);
var filter = Expression.Lambda<Func<IEnumerable<T>, IEnumerable<T>>>(select, sourceParam);
return filter;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment