运行时唯一标识对象的选项是什么?

5
我需要在运行时为对象附加一个唯一标识符。该标识符必须在应用程序的整个生命周期内保持唯一。我计划在对象模型的基类中使用一个私有成员变量来实现这一点。该变量将在对象初始化时设置,并且其值将在对象的生命周期内保持不变。在应用程序的整个生命周期中,没有其他对象可以拥有相同的标识符。
当然,我可以使用 System.Guid,但每个对象都需要128位的存储空间,我希望消耗更少的资源。我尝试使用 Int32 并使用 System.Environment.TickCount 属性进行初始化,但分辨率不够,有些对象最终被分配了相同的值。
TickCount 的文档说明 TickCount 属性在约 29 天后会滚动到负数,然后在另外 29 天后回到零。我很愿意通过缩短回滚时间来换取更高的分辨率。
我还有其他不知道的选项吗?

3
你担心使用GUID会过度消耗哪些资源?这句话听起来有点像过早优化。我建议先采用使用GUID的解决方案,只有在遇到具体的性能瓶颈时再重新考虑。 - John Bledsoe
我一直在过度思考这个问题。谢谢大家让我回到正轨。 - Michael J
4个回答

14

我建议使用整数值,并在赋值时自动递增它。你可以使用Interlocked.Increment,使此操作线程安全。

很可能,32位整数对于这个任务已经足够大了。我建议使用类似以下的方法:

private static newObjectId = int.MinValue;

private static int GetNextId()
{
    return Interlocked.Increment(ref newObjectId);
}

您可以在基类中使用它来分配一个新的唯一标识符。


不错。您可以将其放入需要ID的类中,并在构造函数中执行赋值操作。 - KeithS

10
为了为对象生成唯一的ID,您可以使用我们方便地提供的名为ObjectIDGenerator的工具: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.objectidgenerator.aspx 请注意,正如注释所指出的那样,对象ID生成器会保持对对象的引用,因此它只适用于您知道将在应用程序生命周期内存活的对象。如果您打算在更短暂的对象上使用此工具,则它并不是一个好的解决方案。 如果您想要构建自己的对象ID生成器,并保持弱引用,那么这并不难。

2
有趣。文档说ObjectIDGenerator旨在用于序列化,其生命周期应与创建它的Formatter相同,并通过维护ID和对象地址之间的关系来工作。从描述中不清楚ObjectIDGenerator对对象的引用是否会防止垃圾回收该对象。您知道它是否使用弱引用,或者在程序的整个生命周期内使用时是否可能成为内存泄漏的源吗? - Jeffrey L Whitledge
1
@Jeffrey:非常好的观点。是的,ID生成器确实保留了对对象的引用。它在内部只是一个简单的哈希表。 - Eric Lippert
我今天学到了新东西...这就是为什么我喜欢StackOverflow的原因。 - Michael J

3

您需要标识符在所有对象之间唯一还是仅在特定类型内唯一?

您有几个选择:

  1. 如果您没有覆盖 Object.GetHashCode(),那么这将为您提供一个相当(但不是100%)可靠的标识符。请注意,虽然(根据文档),这并不保证是唯一的。不过,撞上重复的机会相当低。
  2. 如果您正在覆盖(或需要100%),最简单的解决方案是在您的类中使用 private static long lastObjectId。在基本构造函数中,使用 Interlocked.Increment(ref lasObjectId) 作为当前对象的值。
  3. 如果您需要标识符在对象之间唯一,则可以执行与2类似的操作,但必须使用中央类来管理这些ID。

2
如果唯一性只针对应用程序的生命周期,那么您不能使用一个32位整数,初始化为零,然后在每个对象分配时简单地递增吗?
不需要担心TickCount或任何其他事情。数字“2”在数字中是唯一的;如果您只测试相等性,它与“1”和“3”以及“1,203,718”之间的差异是一样的。

1
你最后一句话提醒了我圣手榴弹的使用说明。 - Adam Robinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接