Does anyone have any idea how I call a lambda expression from within a lambda expression?
If I have:
public class CourseViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public static Expression<Func<Course, CourseViewModel>> AsViewModel = x =>
new CourseViewModel
{
Id = x.Id,
Name = x.Name,
}
}
public class StudentViewModel
{
public int Id { get; set; }
public string Name{ get; set; }
public string PreferredCheese { get; set; }
public IEnumerable<CourseViewModel> Courses { get; set; }
public static Expression<Func<Student, StudentViewModel>> AsViewModel = x =>
new StudentViewModel
{
Id = x.Id,
Name = x.Name,
PreferredCheese = x.PreferredCheese,
Courses = ???I'd like to call the CourseViewModel.AsViewModel here
}
}
In the code above rather than writing the AsViewModel expression within the StudentViewModel as:
Courses = new CourseViewModel
{
Id = x.Id,
Name = x.Name,
}
I'd like to call CourseViewModel.AsViewModel to allow code re-use and to keep the code converting a Course to a CourseViewModel in the CourseViewModel class. Is this possible?
You can just use x.Courses.Select(c => CourseViewModel.AsViewModel(c))
So your whole expression would be:
public static Expression<Func<Student, StudentViewModel>> AsViewModel = x =>
new StudentViewModel
{
Id = x.Id,
Name = x.Name,
PreferredCheese = x.PreferredCheese,
Courses = x.Courses.Select(c => CourseViewModel.AsViewModel(c))
}
If you want to preserve CourseViewModel.AsViewModel
as a nested expression (which you probably do if you're using a LINQ query provider), this gets tricky; you effectively have to build up the AsViewModel
expression in StudentViewModel
by yourself:
using E = System.Linq.Expressions.Expression; // for brevity
// ...
static StudentViewModel()
{
var s = E.Parameter(typeof(Student), "s");
//
// Quick hack to resolve the generic `Enumerable.Select()` extension method
// with the correct type arguments.
//
var selectMethod = (Expression<Func<Student, IEnumerable<CourseViewModel>>>)
(_ => _.Courses.Select(c => default(CourseViewModel)));
var lambda = E.Lambda<Func<Student, StudentViewModel>>(
E.MemberInit(
E.New(typeof(StudentViewModel)),
E.Bind(
typeof(StudentViewModel).GetProperty("Id"),
E.Property(s, "Id")),
E.Bind(
typeof(StudentViewModel).GetProperty("Name"),
E.Property(s, "Name")),
E.Bind(
typeof(StudentViewModel).GetProperty("PreferredCheese"),
E.Property(s, "PreferredCheese")), // LOL?
E.Bind(
typeof(StudentViewModel).GetProperty("Courses"),
E.Call(
((MethodCallExpression)selectMethod.Body).Method,
E.Property(s, "Courses"),
CourseViewModel.AsViewModel))
),
s);
AsViewModel = lambda;
}
The resulting expression tree is equivalent to:
s => new StudentViewModel {
Id = s.Id,
Name = s.Name,
PreferredCheese = s.PreferredCheese,
Courses = s.Courses.Select(x => new CourseViewModel { Id = x.Id, Name = x.Name })
}