我需要对对象列表和任意的sort属性进行排序。如果列表中有多个对象具有该sort属性的相同值,则重复对同一列表进行排序将重新排列具有相同sort属性值的成员。需要明确的是,每次运行排序时,都会生成一个新列表,并且成员的顺序是任意的,不一定与上次对列表进行排序时的顺序相同。有办法避免这种情况吗?
这是一个代码示例:
List<T> myList; // T is arbitrary and I doesn't implement any common interface
PropertyInfo sortPorperty = some property of T
var sortedList = myList.OrderBy(x => sortProperty.GetValue(x));
多次执行此代码将导致对象的顺序不同。
我最初的想法是也按对象本身进行排序
var sortedList = myList.OrderBy(x => sortProperty.GetValue(x)).ThenBy(x => x);
但是据我所知,它将按哈希码排序,并且基本上是对象的内存位置,因此两次运行之间不会相同。还有其他可行的方法吗?
答案 0 :(得分:2)
如果类型是可序列化的,则可以使用对象的序列化作为最终的排序条件。
使用BinaryFormatter为对象生成一个唯一字符串(在此示例中,我将其称为 Idem )并将其用作最终的.ThenBy
排序标准。
在此示例中,我将对象的二进制格式版本转换为base64字符串(可以肯定的是性能开销,还有其他方法可以使二进制版本很好地进行比较,但是我只是在说明一般方法)
我认为这个例子包含了您所要求的一切。没有接口的任意类型,使用属性作为OrderBy标准,并且不依赖于项目的初始顺序来在后续运行中产生相同的输出顺序。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
public static class Extensions
{
// Returns a string unique(TM) to this object.
public static string Idem<T>(this T toSerialize)
{
BinaryFormatter formatter = new BinaryFormatter();
var memoryStream = new MemoryStream();
using (memoryStream)
{
formatter.Serialize(memoryStream, toSerialize);
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
[Serializable()]
public class Person
{
public Person(string name, string secret)
{
this.name = name;
this.secret = secret;
}
private string secret; // some private info
public string Nickname { get { return name; } } // some property
public string name; // some public info
public override string ToString() // a way to see the private info for this demo
{
return string.Format("{0} ({1})", name, secret);
}
}
class Program
{
static void Main(string[] args)
{
// You can rearrange the items in this list and they will always come out in the same order.
List<Person> myList = new List<Person>() {
new Person("Bob", "alpha"),
new Person("Bob", "bravo"),
new Person("Alice", "delta"),
new Person("Bob", "echo"),
new Person("Bob", "golf"),
new Person("Bob", "foxtrot"),
};
PropertyInfo sortProperty = typeof(Person).GetProperty("Nickname");
Random random = new Random();
for (int i = 0; i < 3; ++i)
{
var randomList = myList.OrderBy(x => random.Next());
var sortedList = randomList.OrderBy(x => sortProperty.GetValue(x))
.ThenBy(x => x.Idem()); // Here's the magic "Then By Idem" clause.
Console.WriteLine(string.Join(Environment.NewLine, sortedList));
Console.WriteLine();
}
}
}