我目前正在撰寫一個程式來監控我們網路上的某些計算機。為此,我有一個 Monitor 物件,我制作了一個單例,以確保與之通信的所有函式都獲得相同的資料。此物件維護一個 ComputerData 物件串列,并提供公共函式來添加、洗掉和更新這些物件。
我撰寫了一個快速測驗工具來獲取監視器的實體,然后發送幾個 testdata ComputerData 物件(使用 BYVAL 傳遞它們)
但是我注意到,如果我更改了 testdata ComputerData 物件,在我將它傳遞給監視器之后,存盤在監視器串列中的物件也會更新。就像它已作為 BYREF 傳遞一樣。
Public Class Monitor
Dim lock As New Object
Private _MonitoredComputers As New List(Of ComputerData)
ReadOnly Property MonitoredComputers As List(Of ComputerData)
Get
SyncLock lock
Return _MonitoredComputers
End SyncLock
End Get
End Property
Private Shared ReadOnly _instance As New Lazy(Of Monitor)(Function() New Monitor(), System.Threading.LazyThreadSafetyMode.ExecutionAndPublication)
Public Shared ReadOnly Property Instance As Monitor
Get
Return _instance.Value
End Get
End Property
Public Sub Add(ByVal computer As ComputerData)
SyncLock lock
If _MonitoredComputers.Contains(computer) Then
Throw New Exception($"List already contains {computer}")
Else
_MonitoredComputers.Add(computer)
End If
End SyncLock
End Sub
Public Sub Remove(ByVal computer As ComputerData)
SyncLock lock
If Not _MonitoredComputers.Contains(computer) Then
Throw New Exception($"{computer} is not a member of list")
Else
_MonitoredComputers.Remove(computer)
End If
End SyncLock
End Sub
Public Sub Update(ByVal computer As ComputerData)
If Not _MonitoredComputers.Contains(computer) Then
Add(computer)
Else
Remove(computer)
Add(computer)
End If
End Sub
Private Sub New()
End Sub
End Class
計算機資料物件
Public Class ComputerData
Property Name As String
Property IP As String
Property Online As Boolean
Property TimeAdded As Date
Property LastPing As Date
Property OnlineUser As String
Property LoggedIn As Boolean
Public Overloads Function Equals(ByVal computer As ComputerData) As Boolean
Return computer.IP = IP AndAlso IP = computer.IP
End Function
Public NotOverridable Overrides Function Equals(ByVal obj As Object) As Boolean
Dim temp = TryCast(obj, ComputerData)
If temp IsNot Nothing Then Return Me.Equals(temp)
Return False
End Function
Public Shared Operator =(ByVal c1 As ComputerData, ByVal c2 As ComputerData) As Boolean
Return c1.Equals(c2)
End Operator
Public Shared Operator <>(ByVal c1 As ComputerData, ByVal c2 As ComputerData) As Boolean
Return Not c1 = c2
End Operator
Public Overrides Function GetHashCode() As Integer
Return IP.GetHashCode
End Function
End Class
測驗線束
Public Class TestFE
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim mon As Monitor = Monitor.Instance
Dim td1 As New ComputerData With {
.IP = "192.168.1.1",
.Name = "Test1",
.Online = True}
Dim td2 As New ComputerData With {
.IP = "192.168.1.200",
.Name = "Test3",
.Online = True}
mon.Add(td1)
td1.Name = "test2"
mon.Update(td1)
mon.Add(td2)
td2.Name = "How did this change?"
Dim clist As List(Of ComputerData) = mon.MonitoredComputers
For Each c As ComputerData In clist
ListBox1.Items.Add(c.Name)
Next
End Sub
End Class
預期產出
Test2
Test3
實際輸出
Test2
How did this change?
我知道如何糾正這一點。在監視器中,我將創建一個新的 ComputerData 物件,并將值從傳遞的物件復制到新物件并將其添加到串列中。
我的問題是,為什么撰寫的代碼沒有按我的預期執行?
uj5u.com熱心網友回復:
按值傳遞意味著傳遞變數內容的副本。如果變數是參考型別,則該變數包含對物件的參考。通過值傳遞它意味著傳遞參考的副本,而不是物件的副本。按值傳遞方法引數與將一個變數分配給另一個變數完全相同。如果你這樣做:
Dim var1 As New List(Of String)
Dim var2 = var1
var2.Add("Hello World")
Console.WriteLine(var1.Count)
您希望看到什么顯示?我希望你說的是“1”而不是“0”,因為只有一個List(Of String)物件。如果只有一個物件,那么通過哪個變數訪問它并不重要。就像現實生活中的物體一樣。如果你父親穿一件紅色襯衫,然后你母親的丈夫穿一件藍色襯衫(假設你父母已婚),你希望看到你父親穿什么顏色的襯衫?我希望你說的是“藍色”。不管你怎么稱呼他,他仍然是同一個人。這段代碼與上面基本相同:
Private Sub DoSomething(var2 As List(Of String))
var2.Add("Hello World")
End Sub
和:
Dim var1 As New List(Of String)
DoSomething(var1)
Console.WriteLine(var1.Count)
現在您知道參考 typ4es 的行為方式,再看看您的代碼,最好在除錯器中運行它并觀察會發生什么。
uj5u.com熱心網友回復:
td1并且td2仍然存在于你的作用域中(你在同一個 sub 中宣告它們),所以如果你將它們傳遞給串列,你只添加對這些的參考。物件上的任何更改都會反映在串列項中,因為它們是相同的。另一方面,mon.Update(td1)在這種情況下是多余的。
只要背景關系存在,您宣告的變數就會存在。
只是為了測驗:
mon(0).Equals(td1) 'should be true
mon(1).equals(td2) 'should be true as well
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/453918.html
標籤:VB.net
