CodeProject - ObjectComparer(对象比较器)

作者: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:

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

None.gif public  ObjectComparer( string [] fields,  bool [] descending)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    Fields 
= fields;
InBlock.gif    Descending 
= descending;
ExpandedBlockEnd.gif}

None.gif

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

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

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

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

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

None.gif public   int  Compare( object  x,  object  y)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
//Get types of the objects
InBlock.gif
    Type typex = x.GetType();
InBlock.gif    Type typey 
= y.GetType();
InBlock.gif
InBlock.gif    
for(int i = 0; i<Fields.Length; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
//Get each property by name
InBlock.gif
        PropertyInfo pix = typex.GetProperty(Fields[i]);
InBlock.gif        PropertyInfo piy 
= typey.GetProperty(Fields[i]);
InBlock.gif
InBlock.gif        
//Get the value of the property for each object
InBlock.gif
        IComparable pvalx = (IComparable)pix.GetValue(x, null);
InBlock.gif        
object pvaly = piy.GetValue(y, null);
InBlock.gif
InBlock.gif        
//Compare values, using IComparable interface of the property's type
InBlock.gif
        int iResult = pvalx.CompareTo(pvaly);
InBlock.gif        
if (iResult != 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//Return if not equal
InBlock.gif
            if (Descending[i])
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//Invert order
InBlock.gif
                return -iResult;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return iResult;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
//Objects have the same sort order
InBlock.gif
    return 0;
ExpandedBlockEnd.gif}

None.gif

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

None.gif Person[] personArray  =   new  Person[]
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
new Person("Joey"21),
InBlock.gif    
new Person("Johnny"30),
InBlock.gif    
new Person("Marky"28),
InBlock.gif    
new Person("C.J."28),
InBlock.gif    
new Person("Joey"25),
InBlock.gif    
new Person("Dee Dee"33)
ExpandedBlockEnd.gif}
;
None.gif

And then we can sort in any field we want:

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

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

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.

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值