Reputation: 10008
I have code like following:
switch(sort.Column)
{
case "code":
model = (sort.Direction == SortDirection.Ascending)
? model.OrderBy(x => x.code)
: model.OrderByDescending(x => x.code);
break;
case "name":
model = (sort.Direction == SortDirection.Ascending)
? model.OrderBy(x => x.name)
: model.OrderByDescending(x => x.name);
break;
..............
}
I have about 10-15 fields (like 'code' and 'name') and I do not want to copy and paste similar code with only one difference - field name.
Is there method to generalize query somehow?
Upvotes: 5
Views: 1344
Reputation: 27282
You can use reflection (this assumes code
and name
are properties; if they are public variables, you'll have to modify accordingly):
model = (sort.Direction == SortDirection.Ascending)
? model.OrderBy( x => x.GetType()
.GetProperty( sort.Column ).GetValue( x, null ) ) :
: model.OrderByDescending( x => x.GetType()
.GetProperty( sort.Column ).GetValue( x, null ) );
As Dunc points out in the comments below, this approach forces reflection at each step of the enumeration, and reflection is expensive as operations go. If your collection is homogeneous, you can achieve better performance by moving the reflection out of the enumeration. If your model
contains only elements of type Foo
, you can do the following instead:
var prop = typeof( Foo ).GetProperty( sort.Column );
model = (sort.Direction == SortDirection.Ascending)
? model.OrderBy( x => prop.GetValue( x, null ) ) :
: model.OrderByDescending( x => prop.GetValue( x, null ) );
Please not that this will throw a TargetException
if your collection is not homogeneous.
Upvotes: 7
Reputation: 11955
This would get you started, but you could also use reflection to get the property name via the Column, if the property and column match exactly.
// inline function
Func<Func<Model, TResult>, Model> Order = criteria =>
{
return (sort.Direction == SortDirection.Ascending)
? model.OrderBy(criteria)
: model.OrderByDescending(criteria);
}
... code down to switch ...
This would shorten your name case to:
model = Order(x => x.name);
But with reflection, you could do it without the switch, but I'm a little weak on reflection, so I'll leave it to someone else if they want.
Upvotes: 3
Reputation: 442
As 'No Such IP' says, there are patterns for this - command dispatcher/factory method/etc. Those are valid choices. But sometimes these can just hide the complexity. My suggestion is to look at using dynamic linq. Here is a link to get you started: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You can also roll your own if you desire as it is not overly complicated. Create extension methods of your own that allow you to pass in parameters (i.e. sort direction, sort column) about your order and within that extension method, build up your own order by statement using the system.linq.expressions namespace. Here is an example of that as well: http://ronniediaz.com/2011/05/24/orderby-string-in-linq-c-net-dynamic-sorting-of-anonymous-types/
Upvotes: 1