2008-09-15 53 views
2

我想在每次實例化新類時爲該類提供唯一標識。例如有一個名爲Foo類我想能夠做到以下在實例化時賦予類唯一標識:.Net

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

和將獲得一個唯一的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也是隻讀的,你應該可以在構造函數中更改只讀變量。)我認爲這也與它被共享有關。任何解決方案(希望不kludgy赫赫)或解釋爲什麼這將無法正常工作將被接受。重要的部分是我想要兩個變量(或者如果有一種方法只有一個更好,但我認爲這是不可能的)在對象初始化後是不可變的。謝謝!

回答

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 

代替存儲內部美孚一個int,你存儲類型FooId的對象。通過這種方式,您可以完全控制可以和不可以對id執行的操作。

爲了保護我們的FooId不被操縱,它不能被繼承,除了構造函數和int的getter之外,沒有其他方法。而且,變量_nextId對於FooId是私有的,並且不能從外部進行更改。最後,FooId的構造函數中的SyncLock確保它永遠不會並行執行,從而保證進程內的所有ID都是唯一的(直到你敲擊MaxInt :))。

-1

它可能會拋出一個錯誤,因爲你永遠不會初始化_nextId任何東西。它需要有一個初始值,然後才能安全地加1。

0

它引發錯誤,因爲_nextId是ReadOnly。刪除。

編輯: 正如您所說,ReadOnly變量可以在構造函數中更改,但如果它們是Shared,則不會。這些只能在共享構造函數中更改。例如:

Shared Sub New() 
    _nextId = 0 
End Sub 
+0

你讀過這個問題了嗎?他希望_nextId只讀。 – TheSmurf 2008-09-15 15:41:45

+0

我不知道你可以評論答案,所以忽略我的回答,這是有道理的。我打開這個開放了一下,看看是否有其他人有任何有趣的想法,但我會接受這個答案。謝謝,我不知道共享讀取只能在共享構造函數中修改。 – Nicholas 2008-09-15 15:49:01

5

此設計容易出現多線程問題。我強烈建議使用Guids作爲你的ID(Guid.NewGuid())。如果您絕對必須使用整數,請查看Interlocked課程。您可以將所有遞增和Id邏輯封裝在基類中,這樣您只能在一個位置訪問ID生成器。

1

ReadOnly變量必須在對象構造期間被初始化,然後在之後不能被更新。這將不會編譯,因爲您無法爲此增加_nextId。 (共享ReadOnly變量只能在共享構造函數中分配)。

因此,如果您刪除了_nextId定義的ReadOnly修飾符,則應該沒問題。

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 
0

共享整數不應是隻讀的。標記爲readonly的字段只能分配一次,並且必須在構造函數退出之前分配。

由於共享字段是私人的,所以沒有任何外部因素會改變該字段的危險。

0

你說「這不會編譯,因爲它會引發錯誤」,但從來沒有說過那個錯誤是什麼。

共享變量是靜態的,所以在內存中只有一個可供所有實例訪問的副本。您只能從一個靜態(共享)構造函數修改靜態只讀(共享只讀)(新建()),所以你可能想是這樣的:

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。

0

我發佈了一個similar question,它關注於設置唯一實例ID的多線程問題。你可以查看它的細節。