小新的技术天地

Make It Works !

博客园 首页 新随笔 联系 订阅 管理

作者:Diego Mijelshon                    翻译:小新0574

原文以代码链接:http://www.codeproject.com/csharp/objectcomparer.asp

Introduction

Sooner or later, you will have an array of objects you'd like to sort. Unlike simple types like strings or integers, your objects usually have several properties you or your user want to sort on.

迟早,你会想排序一组对象。不像strings或者integers这样的简单类型,你或者你的用户想根据你的对象们的一些属性来排序。

This article explains how to write a simple class which works with Array.Sort() to sort arrays of objects on dinamically selected fields. It's very similar to what DataView.Sort does for DataTables.

这篇文章解释了怎么编写一个使用Array.Sort()的简单的类根据动态选择的字段来排序一组对象。这很像DataView.Sort DataTables所做的。

Background

Back in the old C times, when you wanted to use the standard sort or search functions you had to write a function to compare two objects of the desired type. The function received pointers to the objects, and returned -1, 0 or 1 when the first value was smaller, equal or bigger than the second.

回到以前的C语言时代,当你想使用标准的sort或者search函数,你必须写一个函数来比较所要的类型的两个对象。函数接受指向对象的指针,在第一个值为较小,相等,较大于第二个值时返回-1,0,1

You will then pass your function to the C sort function, using a function pointer (something similar to .NET's delegates).

然后,你使用一个函数指针(这是一个跟.NETdelegates相似的东东)把你的函数传给C sort函数。

This dirty but efficient technique allowed to create a single array sort function, that worked with any type of objects you wrote a comparer for.

这种丑陋的但却很有效的技术允许创建一个单独的数组排序函数,这可以运作于你写来比较的任何类型的对象。

Thinking in objects

In .NET, the approach to this problem is very similar. The Array.Sort method uses an IComparer with a method called Compare, that receives two objects and returns exactly the same as our old C comparer.

.NET里,问题的解决办法十分相似。Array.Sort 方法使用IComparer接口的Compare方法,这个方法接受两个对象,返回值就像我们的C comparer一模一样。

The class

The criteria to sort an array of objects is usually formed by the name of the fields, and an indication of ascending or descending order (like an SQL "ORDER BY" clause).

排序一组对象的标准通常由域的名称形成,同时指出是升序还是降序。

So, the constructor of our class accepts exactly those parameters:

所以,我们的类的构造器就接受那些参数:

public ObjectComparer(string[] fields, bool[] descending)
{
    Fields 
= fields;
    Descending 
= descending;
}


To make it easier to use, I also implemented a constructor for "all ascending" fields:

为了易于使用,我实现了一个为“只为升序”的字段的构造器:

public ObjectComparer(params string[] fields) : this(fields, new bool[fields.Length]) {}

The alternate constructor just calls the first one with an array of false booleans for the descending parameter. Remember that, since bools are structs, they are initialized to 0 (false) on array creation.

两个构造器中只有给descending参数一个组false布尔值时才调用第一个构造器。记住一点,虽然bools是结构,但是在一组创建时初始化为0 (false)

Now, the method that does all the work

现在,这个方法做了所有工作

public int Compare(object x, object y)
{
    
//Get types of the objects
    Type typex = x.GetType();
    Type typey 
= y.GetType();

    
for(int i = 0; i<Fields.Length; i++)
    
{
        
//Get each property by name
        PropertyInfo pix = typex.GetProperty(Fields[i]);
        PropertyInfo piy 
= typey.GetProperty(Fields[i]);

        
//Get the value of the property for each object
        IComparable pvalx = (IComparable)pix.GetValue(x, null);
        
object pvaly = piy.GetValue(y, null);

        
//Compare values, using IComparable interface of the property's type
        int iResult = pvalx.CompareTo(pvaly);
        
if (iResult != 0)
        
{
            
//Return if not equal
            if (Descending[i])
            
{
                
//Invert order
                return -iResult;
            }

            
else
            
{
                
return iResult;
            }

        }

    }

    
//Objects have the same sort order
    return 0;
}

Note that I don't implement ANY error-checking code. It's such a simple class that it's not worth it. Be sure to call it with correct parameters (existing properties, and two same-size parameter arrays).

注意我们没有实现任何查错的代码。这是个简单的类,不值得这么做(查错)。自己保证使用正确的参数调用它(已存在的属性,两个同样大小的参数数组)。

Comparing apples and bananas?

The key here, is that the two objects don't have to be the same type, as long as they implement the same property, and the property is a type that implements IComparable. So, you could sort Controls based on their TabIndex, since it's an Int32.

关健在于两个对象必须要是相同的类型,只要他们实现相同的属性,而且这个属性是实现IComparable的一个类型。所以,你可以根据ControlsTabIndex来排序Controls,即使它是一个Int32.

Using the code

First build the ObjectComparer library, and then open the PersonSort project.

首先构建ObjectComparer库,然后打开PersonSort工程。

This sample project implements a simple class, Person, which represents a person with a Name (string) and an Age (int). We first create an array of persons:

这个示例工程实现了一个简单的类,Person,以一个Name (string) 和一个 Age (int)来呈现一个person

Person[] personArray = new Person[]
{
    
new Person("Joey"21),
    
new Person("Johnny"30),
    
new Person("Marky"28),
    
new Person("C.J."28),
    
new Person("Joey"25),
    
new Person("Dee Dee"33)
}
;

And then we can sort in any field we want:

然后我们就可以任何字段来进行排序:

//Sort by Age
Array.Sort(personArray, new ObjectComparer("Age"));
//Sort by Name, Age
Array.Sort(personArray, new ObjectComparer("Name""Age"));
//Sort by Name, Age DESC
Array.Sort(personArray, new ObjectComparer(
    
new string[]{"Name","Age"},
    
new bool[]{false,true}
    ));

Conclusion

ObjectComparer is a nice tool for sorting arrays of objects on programmer or user request.

ObjectComparer是一个不错的工具来为程序员或用户的要求排序一组对象。

Whenever you create this kind of utility class, it's important to create good constructors, so they can be created and used in just one line.

无论什么时候你创建这种功能类,重要的是创建好的构造器,这样它们能在仅仅一行创建和使用。

posted on 2005-05-06 23:50  小新0574  阅读(3470)  评论(2编辑  收藏  举报