複製Object 陣列
Object 是一個存放指標的變數,她用來指向一個記憶體區塊,表示該變數在運作時會影響該區塊的資料。
下面這段程式碼表現出Visual Basic 的睿智,因為他知道當一個Object 變數去存取另一個變數資料時,寫手希望這個Object 變數是跟來源變數分開的,也就是說,該Object 變數變動時並不會影響到原始資料,有點像兩者分立的感覺。這是Objcet 變數已經自動從來源變數使用Copy 函式,將記憶體資料複製到該Object 變數中。
]Dim testInteger As Integer = 1
]Dim testObject As Object = testInteger //在這裡,testObject 理論上要存入指向testInteger 的指標,不過這不是大多數寫手所希望的,因此Visual Basic 自動將該testInteger 的資料複製到testObject 的存放位置,testObject 得到「非指標的1」。
]testObject -= 1 //上面已經說過了,現在的testObject 所存放的是「非指標的1」,這代表著testObject 跟testInteger 之間不存在任何關係,現在testObject 減少1,是直接對testObject 所對應記憶體位置內的資料做修改,testObject 得到0,testInteger 維持1。
]MsgBox(testInteger) //MsgBox 裡顯示"1"。
]MsgBox(testObject) //MsgBox 裡顯示"0"。
這個功能好嗎? 對初學者,是;對寫手,非。因為Visual Basic 這樣完全不能控制地自動複製已經扼殺了Object 原本所存在的指標性能,因此網路上才會有很多寫手對此抱怨,原因是Visual Basic 沒有像C++ 一樣好用的指標──但從另一方面來說,微軟這麼做是對的,因為在未來的科技裡,為了解決運算速度過慢而誕生的指標不再常用,寫手們必須漸漸習慣這種環境。
那麼,真的不能用指標? 在Visual Basic 2005 之前的版本,是存在VarPtr、StrPtr、ObjPtr 似乎是存在這樣的功能,不過到了2005 以後,似乎又不能使用了。至於Object,則有一個漏洞讓我們有機可趁──只不過這個漏洞會大量改變對此方面的寫作語法,因此還是盡量少用。
這個漏洞出自於Visual Basic 的Array。沒錯,微軟Visual Basic 最令其他程式語言望塵莫及的功能之一就是萬能的字串型別String,而字串正好又是Char 的陣列型態(即使在Visual Basic 裡兩者被些微分別開來),這個屬於Char 的Array 十分好用,幾乎是無所不能,並且大部分的型別都有ToString 這個函式(雖然這跟String 厲不厲害無關),掌控陣列型態字元成為String 的Visual Basic 卻在Array 辨識方面漏洞百出。
當上面的程式碼以Object 陣列來嘗試的時候,指標性能恢復。因為Visual Basic 再度看不懂這是個Object 陣列。
]Dim testInteger As Integer() = New Integer() {1}
]Dim testObject As Object() = testInteger //這個時候,Visual Basic 只覺得一個陣列被存入另一個陣列裡,並不會檢查到裡面是Object 必須使用複製的函式,因此testObject 得到的是對應到testInteger 上的指標。
]testObject(0) -= 1 //testObject 動用了指標特性修改指向記憶體位置的資料數據,這個指標正好指向testInteger(0) 這個位置,testInteger(0) 得到0。
]MsgBox(testInteger(0)) //MsgBox 裡顯示"0"。
]MsgBox(testObject(0)) //MsgBox 裡顯示"0"。
哇! 這豈不是太爽了? 只要會被指標牽扯上的變數都要宣告成只有一個單位的陣列! 目前,以我個人的知識來看,是。
但是當我發現這個問題的時候,我更想知道,如何讓他消失其指標特性? 微軟Visual Basic 開發人員不是沒有腦袋的,她們當然發現了這個問題,並且彌補她。她們在Array 型別裡創造了一個函式叫做Copy。這個函式是公開函式,請使用參數Array.Copy(來源陣列, 目標陣列, 數量)。
]Dim testInteger As Integer() = New Integer() {1}
]Dim testObject(0) As Object
]Array.Copy(testInteger, testObject, 1)
別懷疑,上面的程式碼的確沒有寫完,那是因為這個函式(事實上應該是一個Sub) 不合我意,第一,她不會自動修改送入的目標陣列的索引大小──即使我也想不出任何方法來解決,第二,那個數量是很不可靠的,因為我們如果需要選擇索引的話,不會每次都是從第一個索引開始(或者搞不好是最後一個索引位置? 本人沒有測試...... ),第三,這個函式名稱很冗長,"Copy" 四個字母是還好,可是前面還要加個"Array",字數便多了,而且他是以一個Sub 型態出現,不會傳回值──如果妳問這是否重要,我只能說美觀與否對於一個真正熱在其中的寫手是很重要的──不過前面所說的「美觀」也不過是本人小小的看法而已。(順便說,那個「熱在其中」並沒有打錯,熱是指熱情、投入。)
以前介紹過十分神奇的函式,她解決了微軟在陣列上的許多漏洞使得未知型別的陣列傳送更具安全性(雖然原理很簡單),並且,該函式也擁有一個十分神奇的名字──由來是她可以在Visual Basic 提出警告認為程式碼有問題時仍正常運作──"God"。
我們當然可以用God 來取代上面的Array.Copy啦! 第一,這個函式同樣沒有修改送入目標陣列的索引大小的能力,平手,第二,不需要送入"數量" 參數,因為整個陣列會被複製,第三,函式名稱十分簡潔,"God" 甚至比"Copy" 少一個字母! 並且,她是以Function 傳回值的方法存在。
]Dim testInteger As Integer() = New Integer() {1}
]Dim testObject(UBound(testInteger) - LBound(testInteger)) As Object
]testObject = God(testIntegr, testObject)
]testObject(0) -= 1
]MsgBox(testInteger(0)) //MsgBox 裡顯示"1"。
]MsgBox(testObject(0)) //MsgBox 裡顯示"0"。
