a generic sort by string field method
I've got a situation here and I'm not sure what the best way of proceeding is...
My front end code (ASP.NET) constantly gets lists of business objects for populating UI components. Recently, I implemented a Natural Sort that I want to use for all types of these lists. (currently it just sorts Lists of Strings) Depending on the type of business object, I need to sort on a different field name. The field always contains a string. I know the field name at compile time. The business objects do not hav开发者_运维技巧e a common parent aside from Object.
I'd like to have one method which can do this for an Enumerable of any type. I cannot change the code for the underlying business objects. How would you go about this?
Something like Linq's orderby?
You'd have to implement your natural sort in an IComparer, but then you'd just use:
Items.OrderBy(i => i.SomeStringField, NaturalSorter);
You could use an anonymous function to retrieve the correct string. This means that you would pass both the list of objects and a lambda expression or anonymous method delegate to extract the string to your sorting method.
sort(listOfFoos, o => ((Foo) o).name());
I've not used much C# myself recently, so others can probably shout me down if that won't work.
You could use reflection:
private string GetStringValue(object input, string propertyName)
{
PropertyInfo pi = typeof(input).GetProperty(propertyName);
return pi.GetGetMethod().Invoke(input) as String;
}
This will get the value of a given property for your object, and you can then apply sorting based on this.
You need to create a key selector. Take a look at Enumerable.OrderBy. Its second parameter is the key selector. Implement this to take into account the type of the business object, e.g.:
delegate (object o)
{
if (o is BizType1) return ((BizType1)o).Property1;
else if (o is BizType2) return ((BizType2)o).Property2;
}
Since you don't have a common type on which you can access the properties in a strongly-typed manner, you can't use OrderBy
directly as suggested in the other answers.
You will need to use reflection to get a reference to the property object and ask it to retrieve its value on each item in the sequence:
public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
this IEnumerable<TSource> source,
string propertyName)
{
var property = typeof(TSource).GetProperty(propertyName);
return source.OrderBy(item => (string) property.GetValue(item, null));
}
Of course, if at runtime you know the field and the exact type of list to sort, you should use the strongly-typed overload of OrderBy
instead. This suggestion is only if you don't know the kinds of items in the list to sort (i.e. IEnumerable<object>
).
For each business object, implement IComparable<T>
interface.
Then use LINQ OrderBy
method, which will automatically use your method for sorting.
If you can't or don't want to include sorting logic in business object classes, you can as well implement an IComparer<T>
and pass it to an OrderBy
overload.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//lets say this is the list that you have you mah have more fields
List<Person> people = new List<Person>();
people.Add(new Person(25, "Jhon"));
people.Add(new Person(22, "Antonio"));
people.Add(new Person(21, "Waid"));
people.Add(new Person(21, "Chris"));
people.Add(new Person(26, "Lacy"));
people.Add(new Person(21, "Albert"));
people.Add(new Person(45, "Tom"));
people.Add(new Person(65, "Bob"));
var query = from a in people // crate a query from your list in this case the list is people
where a.age > 18 && a.age < 50 // select just people that has an age greater than 0 and less than 100
// maybe you want to filter some results if you dont then delete this line.
orderby a.name // order the results by their name
select a.name; // then select just the name. if you type select just a then query will
// contain a list of ages too.
// loop though the results to see if they were ordered
foreach (string name in query)
{
Console.WriteLine(name);
}
Console.Read();
}
}
// I created this class because I dont know what your list contains I know it has a string therefore I added a string
// you may add more properties and it will still work...
class Person
{
public int age;
public string name;
public Person(int a, string n)
{
age = a;
name = n;
}
}
}
精彩评论