2013-01-07 69 views
1

我創建了下面的遞歸程序來獲取所有選中的節點在一個TreeView:將對象ByRef傳遞給sub而不是使用函數 - 這是不好的編程習慣......爲什麼?

Sub GetAllCheckedNodes(ByVal tn As TreeNode, ByRef NodesList As List(Of TreeNode)) 
     If tn.Checked Then NodesList.Add(tn) 

     For Each nd As TreeNode In tn.Nodes 
      GetAllCheckedNodes(nd, NodesList) 
     Next 
    End Sub 

基本上,我用這將是宣佈一個空List(Of Treenode),然後將其傳遞到這個例程的第二個參數的方式。 我的問題是,我被告知這是「不是很好」的編程練習 - 爲什麼會出錯?

這似乎是我可以想出的最優雅的解決方案來實現這個工作。

回答

3

沒有必要通過列表ByRef - 它已經是一個引用類型。只要按價值傳遞它,你仍然可以添加選中的項目。

+1

LO和BEHOLD !!! - 沒有'ByRef'就可以工作......我想我對'Byref'的含義有一個不正確的想法。我一直認爲這意味着你正在處理原始變量,而「ByVal」給你一個變量的副本,而不是......如果你願意,你能指點我瞭解差異的正確方向/解釋使用請問ByRef'? –

+0

當你傳遞一個引用類型'ByRef'時,你傳遞了對引用的引用。它將允許您更改變量以引用*不同*列表。我會挖掘一個鏈接... –

+0

@JohnBus​​tos這正是它的意思。在這種情況下,變量不是列表本身,因爲'List'是一個引用類型。該變量除了提供實際列表的位置...在其他地方沒有任何關係。無論您是通過值還是通過引用複製該引用*都無關緊要,因爲您不會更改引用的內容,而只是更改引用指向的對象。 – Servy

1

問題是來自其他程序員的期望以及您依賴副作用(即傳入參數的更改)的事實。

當有人看到一個Get*,期望的是它會返回一個值。

您仍然可以遞歸函數而不必依靠更改傳入的參數。

2

這裏比較常見的解決方案是,不要改變傳入的集合,而是返回表示符合條件的所有節點的集合/序列。我個人認爲IEnumerable很適合這種情況,因爲您可以使用迭代器塊或只是將結果連接在一起,以便該方法有選擇地添加自身,然後從遞歸調用中返回所有內容。

這有幾個好處。首先,打電話更容易;不需要創建列表,傳遞它,確保沒有線程/併發修改問題,然後稍後使用它,只需調用該方法並使用結果即可。

+0

一如既往地感謝@Servy - 很有道理......我以爲我不需要在程序中聲明一個變量,而是通過這種方式來節省空間,但如果這是更好的編程練習,那就這樣吧! - 謝謝!!! –

+0

...我很抱歉@Servy,如果我可以選擇2個答案,我肯定會爲你和Jon投票,因爲你們都幫助完全解釋我的問題並進一步瞭解我的知識 - 我非常感謝你,並且簡單地選擇Jon的因爲他先回答。謝謝你,塞維! –

相關問題