开发者

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;
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜