C# Refactoring gigantic switch statement for ordering with LINQ

353 views Asked by At

My problem is repetitive code: a not so DRY switch statement.

So I have a table with 12 columns that can be ordered by descending or ascending on click. My current solution is the use of a switch statement that checks which column was clicked.

The sortable properties:

enter image description here

This is the page where if a user clicks on a head the table gets ordered:

enter image description here

The SortByColumn property comes in a string. SortAscending boolean comes in from a @Html.CheckBoxFor.

enter image description here

You see where this is going? I have 12 columns that can be ordered, so this switch can get very lengthy and unmaintainable. So my question is, is it possible to refactor this with reflection or in some other way?

4

There are 4 answers

0
André Snede On BEST ANSWER

The OrderBy function works by letting you return the property it should sort on, it will be called foreach item in the list.

Instead of hardcoding it, we can use reflection instead:

public ActionResult Index(AgentReportViewModel vm)
{
    var b = Agent.GetAgents();
    vm.Agents = vm.SortAscending 
        ? b.OrderBy(x => GetValueByColumn(x, vm.SortByColumn))
        : b.OrderByDescending(x => GetValueByColumn(x, vm.SortByColumn));
    return View(vm);
}

public object GetValueByColumn<T>(T x, string columnStr)
{
    // Consider caching the property info, as this is a heavy call.
    var propertyInfo = x.GetType().GetProperty(columnStr);    
    return propertyInfo.GetValue(x, null);
}
0
DonBaton On

Take look at System.Linq.Dynamic (NuGet Package Available).

Then you can do just:

string sortingString = string.Format("{0} {1}",vm.OrderByColumn, vm.SortAscending ? "ASC" : "DESC");
vm.Agents = Agent.GetAgents().OrderBy(sortingString).ToList();
0
sangram parmar On

Try this:

var SortByColumnStr = "Answer"; //Dynamic string
var propertyInfo = typeof(Agent).GetProperty(SortByColumnStr);    
List<Agent> b.OrderBy(x => propertyInfo.GetValue(x, null));

Reference: https://stackoverflow.com/a/7265394/1660178

0
Parthasarathy On

You can use expression trees for this scenario.

public static Func<Agent, object> GetOrderBySelector(string propertyName)
{
    var parameter = Expression.Parameter(typeof(Agent), "a");
    var property = Expression.Property(parameter, propertyName);
    // a => a.PropertyName is a unary expression
    var unaryExpression = Expression.Convert(property, typeof(object));
    // Create the lambda for the unary expression with the given property 
    // information and compile to return the actual delegate.
    return Expression.Lambda<Func<Agent, object>>(unaryExpression, parameter).Compile();
}

Usage:

b.OrderBy(vm.SortByColumn) 

or

b.OrderByDescending(vm.SortByColumn) 

Hope this helps.