I have a list of sorts stored in this format:
public class ReportSort
{
public ListSortDirection SortDirection { get; set; }
public string Member { get; set; }
}
And I need to turn it into a lambda expression of type Action<DataSourceSortDescriptorFactory<TModel>>
So assuming I have the following collection of Report Sorts as:
new ReportSort(ListSortDirection.Ascending, "LastName"),
new ReportSort(ListSortDirection.Ascending, "FirstName"),
I would need to transform it into such a statement to be used like so:
.Sort(sort => {
sort.Add("LastName").Ascending();
sort.Add("FirstName").Ascending();
})
And the sort method signature is:
public virtual TDataSourceBuilder Sort(Action<DataSourceSortDescriptorFactory<TModel>> configurator)
So I have some method right now:
public static Action<DataSourceSortDescriptorFactory<TModel>> ToGridSortsFromReportSorts<TModel>(List<ReportSort> sorts) where TModel : class
{
Action<DataSourceSortDescriptorFactory<TModel>> expression;
//stuff I don't know how to do
return expression;
}
...and I have no idea what to do here.
EDIT: Answer is:
var expression = new Action<DataSourceSortDescriptorFactory<TModel>>(x =>
{
foreach (var sort in sorts)
{
if (sort.SortDirection == System.ComponentModel.ListSortDirection.Ascending)
{
x.Add(sort.Member).Ascending();
}
else
{
x.Add(sort.Member).Descending();
}
}
});
I was thinking at first I had to dynamically build a lambda expression from scratch using the Expression class. Luckily that wasn't the case.
...and I have no idea what to do here.
Well, reason it out.
What have you got in hand? A List<ReportSort>
called sorts
.
What do you need? An Action<Whatever>
.
You've already taken the first step: you've make a method that takes the thing you have and returns the thing you need. Great first step.
Action<DataSourceSortDescriptorFactory<TModel>> expression;
//stuff I don't know how to do
return expression;
And you've called out what you don't know how to do -- yet. This is a good technique.
Start by filling in something that compiles but doesn't work properly.
Action<DataSourceSortDescriptorFactory<TModel>> expression =
sort => {
sort.Add("LastName").Ascending();
sort.Add("FirstName").Ascending();
};
return expression;
Excellent. Now you have a compiling program which means you can run your tests and verify that if this case is expected, the test passes, and if anything else is expected, the test fails.
Now think, what have I got in hand? I've got a list of stuff, and I'm doing an Action
. That means that a side effect is happening, probably involving every item on the list. So there's probably a foreach
in there somewhere:
Action<DataSourceSortDescriptorFactory<TModel>> expression =
sort => {
sort.Add("LastName").Ascending();
sort.Add("FirstName").Ascending();
foreach(var sort in sorts) {
// Do something
}
};
return expression;
Compile it. It fails. Ah, we have confused the sort we are adding to with the new sort we are adding. Fix the problem.
Action<DataSourceSortDescriptorFactory<TModel>> expression =
existingSort => {
existingSort.Add("LastName").Ascending();
existingSort.Add("FirstName").Ascending();
foreach(var newSort in sorts) {
// Do something
}
};
return expression;
Great, now again we are in a position to compile and run tests.
The pattern here should be clear. Keep it compiling, keep running tests, gradually make your program more and more correct, reason about the operations you can perform on the values that you have in hand.
Can you finish it off?