每次实例化一个新的时候,我想给一个类一个唯一的ID。例如,对于名为Foo的类,我希望能够执行以下操作
dim a as New Foo()
dim b as New Foo()
并且a将获得唯一ID并且b将获得唯一ID。 id只需要在运行时是唯一的,所以我只想使用整数。我已经找到了一种方法来做到这一点(并且这是警告)我不希望能够从任何地方更改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也是readonly你应该能够改变构造函数中的只读变量。)我认为这也与它共享它有关。任何解决方案(希望不是kludgy hehe)或解释为什么这不起作用将被接受。重要的部分是我想要两个变量(或者如果有一种方法只有一个甚至更好但我认为不可能)在初始化对象后是不可变的。谢谢!
答案 0 :(得分:5)
此设计容易受到多线程问题的影响。我强烈建议您使用Guids作为您的ID(Guid.NewGuid())。如果您绝对必须使用整数,请查看Interlocked课程。您可以将所有递增和Id逻辑包装在基类中,这样您只能在一个位置访问ID生成器。
答案 1 :(得分:2)
请考虑以下代码:
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 :))。
答案 2 :(得分:1)
ReadOnly变量必须在对象构造期间初始化,然后才能更新。这不会编译,因为你不能因为这个原因增加_nextId。 (共享ReadOnly变量只能在共享构造函数中指定。)
因此,如果你删除_nextId定义的ReadOnly修饰符,你应该没问题。
答案 3 :(得分:1)
我会这样做。
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
答案 4 :(得分:0)
它会抛出一个错误,因为_nextId是ReadOnly。删除它。
修改强> 正如您所说,ReadOnly变量可以在构造函数中更改,但如果它们是Shared,则不会更改。这些只能在共享构造函数中更改。例如:
Shared Sub New()
_nextId = 0
End Sub
答案 5 :(得分:0)
共享整数不应该是只读的。标记为readonly
的字段只能分配一次,并且必须在构造函数退出之前分配。
由于共享字段是私有的,因此无论如何都不会有任何外部更改字段的危险。
答案 6 :(得分:0)
你说“这不会编译,因为它会抛出错误”,但从未说出错误是什么。
共享变量是静态的,因此在内存中只有一个副本可供所有实例访问。您只能从静态(共享)构造函数(New())修改静态只读(Shared ReadOnly),因此您可能需要这样的内容:
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。
答案 7 :(得分:0)
我发布了一个similar question,专注于设置唯一实例ID的多线程问题。您可以查看详细信息。
答案 8 :(得分:-1)
这可能会引发错误,因为您永远不会将_nextId初始化为任何内容。它需要有一个初始值才能安全地添加1。