在实例化时提供类唯一ID:.Net

时间:2023-01-08 13:58:25

I would like to give a class a unique ID every time a new one is instantiated. For example with a class named Foo i would like to be able to do the following

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

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

and a would get a unique id and b would get a unique ID. The ids only have to be unique over run time so i would just like to use an integer. I have found a way to do this BUT (and heres the caveat) I do NOT want to be able to change the ID from anywhere. My current idea for a way to implement this is the following:

并且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

However this will not compile because it throws an error on _nextId = _nextId + 1 I don't see why this would be an error (because _Id is also readonly you're supposed to be able to change a read only variable in the constructor.) I think this has something to do with it being shared also. Any solution (hopefully not kludgy hehe) or an explanation of why this won't work will be accepted. The important part is i want both of the variables (or if there is a way to only have one that would even be better but i don't think that is possible) to be immutable after the object is initialized. Thanks!

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

9 个解决方案

#1


2  

Consider the following code:

请考虑以下代码:

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 

Instead of storing an int inside Foo, you store an object of type FooId. This way you have full control over what can and cannot be done to the id.

您可以存储FooId类型的对象,而不是在Foo中存储int。通过这种方式,您可以完全控制可以和不能对id执行的操作。

To protect our FooId against manipulation, it cannot be inherited, and has no methods except the constructor and a getter for the int. Furthermore, the variable _nextId is private to FooId and cannot be changed from the outside. Finally the SyncLock inside the constructor of FooId makes sure that it is never executed in parallell, guaranteeing that all IDs inside a process are unique (until you hit MaxInt :)).

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

#2


5  

This design is vulnerable to multithreading issues. I'd strongly suggest using Guids for your IDs (Guid.NewGuid()). If you absolutely must use ints, check out the Interlocked class. You can wrap all incrementing and Id logic up in a base class so that you're only accessing the ID generator in one location.

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

#3


1  

ReadOnly variables must be initialized during object construction, and then cannot be updated afterwards. This won't compile because you can't increment _nextId for that reason. (Shared ReadOnly variables can only be assigned in Shared constructors.)

ReadOnly变量必须在对象构造期间初始化,然后才能更新。这不会编译,因为你不能因为这个原因增加_nextId。 (共享ReadOnly变量只能在共享构造函数中指定。)

As such, if you remove the ReadOnly modifier on the definition of _nextId, you should be ok.

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

#4


1  

I'd do it like this.

我会这样做的。

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

#5


0  

It throws an error because _nextId is ReadOnly. Remove that.

它会抛出一个错误,因为_nextId是ReadOnly。删除它。

Edit: As you say, ReadOnly variables can be changed in a constructor, but not if they are Shared. Those can only be changed in shared constructors. Example:

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

Shared Sub New()
   _nextId = 0
End Sub

#6


0  

The shared integer shouldn't be read-only. A field marked readonly can only ever be assigned once and must be assigned before the constructor exits.

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

As the shared field is private, there is no danger that the field will be changed by anything external anyway.

由于共享字段是私有的,因此无论如何都不会被外部的任何东西改变。

#7


0  

You said that "this will not compile because it throws an error" but never said what that error is.

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

A shared variable is static, so there is only a single copy of it in memory that is accessible to all instances. You can only modify a static readonly (Shared ReadOnly) from a static (Shared) constructor (New()) so you probably want something like this:

共享变量是静态的,因此在内存中只有一个副本可供所有实例访问。您只能从静态(共享)构造函数(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

(I think that's the right syntax in VB.) In C# it would look like this:

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

public class Test
{
   private static readonly int _nextId;
   private readonly int _id;

   static Test()
   {
      _nextId++;
   }

   public Test()
   {
      _id = _nextId;
   }

}

The only problem here is that the static constructor is only going to be called once, so _nextId is only going to be incremented one time. Since it is a static readonly variable you will only be able to initialize it the static constructor, so your new instances aren't going to be getting an incremented _id field like you want.

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

What is the problem you are trying to solve with this scenario? Do these unique IDs have to be integer values? If not, you could use a Guid and in your contructor call Guid.

您尝试使用此方案解决的问题是什么?这些唯一ID必须是整数值吗?如果没有,你可以使用Guid并在你的构造函数中调用Guid。

#8


0  

I posted a similar question that focused on the multithreading issues of setting a unique instance id. You can review it for details.

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

#9


-1  

It's likely throwing an error because you're never initializing _nextId to anything. It needs to have an initial value before you can safely add 1 to it.

它可能会抛出一个错误,因为你永远不会将_nextId初始化为任何东西。它需要有一个初始值才能安全地添加1。

#1


2  

Consider the following code:

请考虑以下代码:

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 

Instead of storing an int inside Foo, you store an object of type FooId. This way you have full control over what can and cannot be done to the id.

您可以存储FooId类型的对象,而不是在Foo中存储int。通过这种方式,您可以完全控制可以和不能对id执行的操作。

To protect our FooId against manipulation, it cannot be inherited, and has no methods except the constructor and a getter for the int. Furthermore, the variable _nextId is private to FooId and cannot be changed from the outside. Finally the SyncLock inside the constructor of FooId makes sure that it is never executed in parallell, guaranteeing that all IDs inside a process are unique (until you hit MaxInt :)).

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

#2


5  

This design is vulnerable to multithreading issues. I'd strongly suggest using Guids for your IDs (Guid.NewGuid()). If you absolutely must use ints, check out the Interlocked class. You can wrap all incrementing and Id logic up in a base class so that you're only accessing the ID generator in one location.

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

#3


1  

ReadOnly variables must be initialized during object construction, and then cannot be updated afterwards. This won't compile because you can't increment _nextId for that reason. (Shared ReadOnly variables can only be assigned in Shared constructors.)

ReadOnly变量必须在对象构造期间初始化,然后才能更新。这不会编译,因为你不能因为这个原因增加_nextId。 (共享ReadOnly变量只能在共享构造函数中指定。)

As such, if you remove the ReadOnly modifier on the definition of _nextId, you should be ok.

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

#4


1  

I'd do it like this.

我会这样做的。

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

#5


0  

It throws an error because _nextId is ReadOnly. Remove that.

它会抛出一个错误,因为_nextId是ReadOnly。删除它。

Edit: As you say, ReadOnly variables can be changed in a constructor, but not if they are Shared. Those can only be changed in shared constructors. Example:

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

Shared Sub New()
   _nextId = 0
End Sub

#6


0  

The shared integer shouldn't be read-only. A field marked readonly can only ever be assigned once and must be assigned before the constructor exits.

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

As the shared field is private, there is no danger that the field will be changed by anything external anyway.

由于共享字段是私有的,因此无论如何都不会被外部的任何东西改变。

#7


0  

You said that "this will not compile because it throws an error" but never said what that error is.

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

A shared variable is static, so there is only a single copy of it in memory that is accessible to all instances. You can only modify a static readonly (Shared ReadOnly) from a static (Shared) constructor (New()) so you probably want something like this:

共享变量是静态的,因此在内存中只有一个副本可供所有实例访问。您只能从静态(共享)构造函数(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

(I think that's the right syntax in VB.) In C# it would look like this:

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

public class Test
{
   private static readonly int _nextId;
   private readonly int _id;

   static Test()
   {
      _nextId++;
   }

   public Test()
   {
      _id = _nextId;
   }

}

The only problem here is that the static constructor is only going to be called once, so _nextId is only going to be incremented one time. Since it is a static readonly variable you will only be able to initialize it the static constructor, so your new instances aren't going to be getting an incremented _id field like you want.

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

What is the problem you are trying to solve with this scenario? Do these unique IDs have to be integer values? If not, you could use a Guid and in your contructor call Guid.

您尝试使用此方案解决的问题是什么?这些唯一ID必须是整数值吗?如果没有,你可以使用Guid并在你的构造函数中调用Guid。

#8


0  

I posted a similar question that focused on the multithreading issues of setting a unique instance id. You can review it for details.

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

#9


-1  

It's likely throwing an error because you're never initializing _nextId to anything. It needs to have an initial value before you can safely add 1 to it.

它可能会抛出一个错误,因为你永远不会将_nextId初始化为任何东西。它需要有一个初始值才能安全地添加1。