1

我正在寻找一种方法来对对象列表(可能的任何类型)进行排序,以便无论对象发生什么,只要它们没有被破坏,顺序保持不变(所以 hashCode 不是一个好主意因为在某些类中它会随着时间的推移而改变),因此我想使用内存中对象的地址,但我不确定这是否总是保持不变(地址是否可以通过垃圾收集调用改变实例?)。但是,我正在寻找对象(任何类型)的属性,只要对象没有被破坏,它们就会保持不变。有吗?如果是,它们是什么?

4

3 回答 3

2

是的,垃圾收集器可以在内存中移动对象,除非您明确要求它不要这样做(通常建议让 GC 做它的事情)。

你需要的是一个边表:创建一个由对象本身作为键的字典,并为值放置你喜欢的任何东西(可以是对象的原始哈希码,甚至是随机数)。排序时,按该侧键排序。现在,例如,如果对象 a 在此字典中的值为“1”,它将始终首先排序 - 无论对 a 进行了哪些更改,因为您将在侧字典中查找键和代码不知道去那里更改它(当然,您要小心保持该数据不可变)。如果没有对对象 a 的其他引用,您可以使用弱引用来确保您的字典条目消失。

于 2009-08-26T12:49:36.863 回答
1

鉴于现在添加到问题(评论)中的详细信息已更新;只需在排序之前复制列表内容...


不,地址不固定。对于任意对象,没有明智的做法。对于您自己的对象,您可以添加一些常见的内容,例如:

interface ISequence { int Order { get; } }
static class Sequence {
    private static int next;
    public static int Next() {
        return Interlocked.Increment(ref next); }
}
class Foo : ISequence {
    private readonly int sequence;
    int ISequence.Order { get { return sequence; } }
    public Foo() {
        sequence = Sequence.Next();
    }
}

有点杂乱无章,但它应该可以工作,并且可以在基类中使用。现在Order是不变的和连续的。但只有AppDomain- 特定的,并不是所有的序列化 API 都会尊重它(在这种情况下,您需要使用序列化回调来初始化序列)。

于 2009-08-26T11:49:50.393 回答
0

当然,只有引用对象才有可能按内存地址排序。因此,并非所有类型都可以以这种方式排序,原始类型和结构不是。

另一种方法是依赖于某个接口,您要求每个实例都可以返回一个 Guid。这是在构造函数中创建的,不会更改。

public interface ISortable
{
  Guid SortId { get; }
}

class Foo : ISortable
{
  Foo()
  {
    SortId = Guid.NewGuid();
  }
  Guid SortId { get; private set; }
}

guid 的优点是它可以在每个类中独立创建。你不需要同步,你只需给每个班级一个ID。

顺便说一句:如果您将 Dictionary 中的对象用作 Key,则它们不得更改其哈希码。它们必须是不可变的。这可能是您可以依赖的约束。


编辑:您可以编写能够保持订购的专业列表。

您可以在从另一个列表创建列表时存储原始订单,然后您可以在任何时间点恢复订单。新项目可以放在最后。(反正有新项目吗?)

或者你做一些更复杂的事情,并将你的列表类曾经见过的任何对象的顺序存储在静态内存中。然后,您可以独立地对所有列表进行排序。但要注意你持有的引用,这将避免对象被 GC 清理。你需要周引用,我认为 C# 中有弱引用,但我从未使用过它们。

更好的办法是把这个逻辑放到一个排序类中。因此,它适用于按您的排序类排序的每个列表。

于 2009-08-26T11:45:08.887 回答