C#中对象的不可变属性

时间:2009-08-26 11:37:20

标签: c# sorting properties immutability

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

3 个答案:

答案 0 :(得分:2)

是的,垃圾收集器可以在内存中移动对象,除非你特别要求它(并且通常建议让GC做它的事情)。

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

答案 1 :(得分: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都会尊重它(在这种情况下,您需要使用序列化回调来初始化序列)。

答案 2 :(得分:0)

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

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

public interface ISortable
{
  Guid SortId { get; }
}

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

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

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


修改:您可以编写能够保持订单的专业列表。

您可以在从其他列表创建列表时存储原始订单,然后您就可以在任何时间点恢复订单。新项目可以放在最后。 (无论如何都有新物品吗?)

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

更好的方法是将此逻辑放入排序类中。因此它适用于已由排序类排序的每个列表。

相关问题