字符串字段方法的通用排序

时间:2011-02-28 16:02:57

标签: c# sorting c#-4.0

我在这里遇到了一个情况,我不确定最好的处理方式是什么......

我的前端代码(ASP.NET)不断获取用于填充UI组件的业务对象列表。最近,我实现了一个自然排序,我想用于所有类型的这些列表。 (目前只是对字符串列表进行排序) 根据业务对象的类型,我需要对不同的字段名称进行排序。该字段始终包含字符串。我在编译时知道字段名称。除了Object之外,业务对象没有共同的父级。

我想有一个方法可以为任何类型的Enumerable执行此操作。我无法更改底层业务对象的代码。你会怎么做?

7 个答案:

答案 0 :(得分:5)

类似于Linq's orderby

你必须在IComparer中实现自然排序,但是你只需要使用:

Items.OrderBy(i => i.SomeStringField, NaturalSorter);

答案 1 :(得分:1)

你可以使用反射:

private string GetStringValue(object input, string propertyName)
{
    PropertyInfo pi = typeof(input).GetProperty(propertyName);
    return pi.GetGetMethod().Invoke(input) as String;
}

这将获取对象的给定属性的值,然后您可以根据此应用排序。

答案 2 :(得分:1)

您需要创建一个键选择器。 Take a look at Enumerable.OrderBy。它的第二个参数是键选择器。实现它以考虑业务对象的类型,例如:

delegate (object o)
{
  if (o is BizType1) return ((BizType1)o).Property1;
  else if (o is BizType2) return ((BizType2)o).Property2;
}

答案 3 :(得分:1)

由于您没有可以强类型方式访问属性的常用类型,因此您无法直接使用其他答案中建议的OrderBy

您需要使用反射来获取对property object的引用,并要求它检索序列中每个项目的值:

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

当然,如果在运行时您知道字段要排序的列表的确切类型,则应使用OrderBy的强类型重载。此建议仅在您不知道要排序的列表中的项目类型时(即IEnumerable<object>)。

答案 4 :(得分:1)

您可以使用anonymous function来检索正确的字符串。这意味着您将传递对象列表和lambda表达式或匿名方法委托以将字符串提取到排序方法。

sort(listOfFoos, o => ((Foo) o).name());

我最近自己并没有使用太多的C#,所以如果不起作用,其他人可能会大喊大叫。

答案 5 :(得分:0)

对于每个业务对象,实现IComparable<T>接口 然后使用LINQ OrderBy方法,它将自动使用您的方法进行排序。

如果您不想或不想在业务对象类中包含排序逻辑,您也可以实现IComparer<T>并将其传递给OrderBy overload

答案 6 :(得分:0)

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