【问题标题】:Giving class unique ID on instantiation: .Net在实例化时为类提供唯一 ID:.Net
【发布时间】:2010-09-09 00:08:04
【问题描述】:

我想在每次实例化一个新类时给一个类一个唯一的 ID。例如,对于一个名为 Foo 的类,我希望能够执行以下操作

dim a as New Foo()
dim b as New Foo()

a 将获得唯一的 ID,b 将获得唯一的 ID。 ids 只需要在运行时是唯一的,所以我只想使用一个整数。我找到了一种方法来做到这一点,但是(这是警告)我不希望能够从任何地方更改 ID。我目前对实现此方法的想法如下:

Public Class test
    Private Shared ReadOnly _nextId As Integer
    Private ReadOnly _id As Integer
    Public Sub New()
        _nextId = _nextId + 1
        _id = _nextId
    End Sub
End Class

但是这不会编译,因为它会引发错误 _nextId = _nextId + 1 我不明白为什么这会是一个错误(因为 _Id 也是只读的,你应该能够在构造函数中更改只读变量。)我认为这也与共享它有关。任何解决方案(希望不是笨拙的呵呵)或解释为什么这不起作用都会被接受。重要的部分是我希望这两个变量(或者如果有一种方法只有一个更好,但我认为这是不可能的)在对象初始化后是不可变的。谢谢!

【问题讨论】:

    标签: .net vb.net


    【解决方案1】:

    我发布了一个similar question,专注于设置唯一实例 ID 的多线程问题。您可以查看它以了解详细信息。

    【讨论】:

      【解决方案2】:

      你说“这不会编译,因为它会抛出一个错误”,但从未说过那个错误是什么。

      共享变量是静态的,因此内存中只有一个副本可供所有实例访问。您只能从静态(共享)构造函数(New())修改静态只读(共享只读),所以您可能想要这样的东西:

      Public Class test
         Private Shared ReadOnly _nextId As Integer
         Private ReadOnly _id As Integer
      
         Public Shared Sub New()
            _nextId = _nextId + 1
         End Sub
      
         Public Sub New()
            _id = _nextId
         End Sub
      End Class
      

      (我认为这在 VB 中是正确的语法。)在 C# 中它看起来像这样:

      public class Test
      {
         private static readonly int _nextId;
         private readonly int _id;
      
         static Test()
         {
            _nextId++;
         }
      
         public Test()
         {
            _id = _nextId;
         }
      

      }

      这里唯一的问题是静态构造函数只会被调用一次,所以 _nextId 只会增加一次。由于它是一个静态只读变量,因此您只能将其初始化为静态构造函数,因此您的新实例不会像您想要的那样获得递增的 _id 字段。

      您想通过这种情况解决什么问题?这些唯一 ID 是否必须是整数值?如果没有,您可以使用 Guid 并在您的构造函数中调用 Guid。

      【讨论】:

        【解决方案3】:

        考虑以下代码:

        Public Class Foo 
            Private ReadOnly _fooId As FooId 
        
            Public Sub New() 
                _fooId = New FooId() 
            End Sub 
        
            Public ReadOnly Property Id() As Integer 
                Get 
                    Return _fooId.Id 
                End Get 
            End Property 
        End Class 
        
        Public NotInheritable Class FooId 
            Private Shared _nextId As Integer 
            Private ReadOnly _id As Integer 
        
            Shared Sub New() 
                _nextId = 0 
            End Sub 
        
            Public Sub New() 
                SyncLock GetType(FooId) 
                    _id = System.Math.Max(System.Threading.Interlocked.Increment(_nextId),_nextId - 1) 
                End SyncLock 
            End Sub 
        
            Public ReadOnly Property Id() As Integer 
                Get 
                    Return _id 
                End Get 
            End Property 
        End Class 
        

        不是在 Foo 中存储一个 int,而是存储一个 FooId 类型的对象。这样您就可以完全控制对 id 可以做什么和不可以做什么。

        为了保护我们的 FooId 免受操纵,它不能被继承,并且除了构造函数和 int 的 getter 之外没有其他方法。此外,变量 _nextId 是 FooId 私有的,不能从外部更改。最后,FooId 构造函数中的 SyncLock 确保它永远不会并行执行,从而保证进程中的所有 ID 都是唯一的(直到您点击 MaxInt :))。

        【讨论】:

        • 锁定类型对象是个坏主意。任何人都可以获得类型对象并锁定它。锁对象应该在类实例中保持私有。此外,锁定然后使用 Interlocked.Increment 是多余的。 Interlocked 类方法是原子的,不需要锁定。
        【解决方案4】:

        共享整数不应该是只读的。标记为readonly 的字段只能分配一次,并且必须在构造函数退出之前分配。

        由于共享字段是私有的,因此该字段不会被任何外部事物更改。

        【讨论】:

          【解决方案5】:

          我会这样做。

          Public MustInherit Class Unique
              Private _UID As Guid = Guid.NewGuid()
              Public ReadOnly Property UID() As Guid
                  Get
                      Return _UID
                  End Get
              End Property
          End Class
          

          【讨论】:

            【解决方案6】:

            ReadOnly 变量必须在对象构造过程中初始化,之后不能更新。这不会编译,因为您不能因此而增加 _nextId。 (Shared ReadOnly 变量只能在 Shared 构造函数中赋值。)

            因此,如果您删除 _nextId 定义上的 ReadOnly 修饰符,应该没问题。

            【讨论】:

              【解决方案7】:

              这种设计容易受到多线程问题的影响。我强烈建议您使用 Guids 作为您的 ID (Guid.NewGuid())。如果您绝对必须使用整数,请查看 Interlocked 类。您可以将所有递增和 Id 逻辑包装在一个基类中,这样您就只能在一个位置访问 ID 生成器。

              【讨论】:

                【解决方案8】:

                它会引发错误,因为 _nextId 是只读的。删除它。

                编辑: 正如您所说,ReadOnly 变量可以在构造函数中更改,但如果它们是共享的则不能。这些只能在共享构造函数中更改。示例:

                Shared Sub New()
                   _nextId = 0
                End Sub
                

                【讨论】:

                • 我不知道您可以对答案发表评论,所以请忽略我在此下方的回复,这是有道理的。我将这个开放一段时间,看看是否有其他人有任何有趣的想法,但我会接受这个答案。谢谢我不知道共享只读只能在共享构造函数中修改。
                【解决方案9】:

                这可能会引发错误,因为您从未将 _nextId 初始化为任何内容。它需要有一个初始值才能安全地加 1。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2015-08-29
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-07-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多