關於自動完成功能的一段會話

已經是下午三點了。太陽已經不再直射軟件開發部的窗戶。在窗前的電腦桌邊,程序員甲斜靠在他的真皮靠背椅上,瞪着天花板。

“怎麼了?”去飲水機倒水路過程序員甲背後的程序員乙說:“你又卡住了?”

“是啊!”程序員甲嘆了口氣,說:“那個該死的自動完成功能問題太多。”他深呼吸了一下,甩甩頭說:“再搞不出來我就得和老闆談談是不是要取消這個功能了。”

“你設置了TextBox類的AutoCompleteCustomSource和AutoCompleteMode屬性?”

“是啊。”

“我也是這麼做的,沒發現什麼問題啊?”

“那是你的數據量小。我的查詢返回的數據量大,全部從數據庫讀出來保存到內存不現實,老闆要求只從數據庫讀匹配當前用戶輸入的數據。”

“聽起來好像很簡單啊?在文本框的TextChange裏面用當前文本作爲過濾條件查詢數據庫,用結果填充一個AutoCompleteStringCollection,然後複製給AutoCompleteCustomSource不就好了。”

“說得輕巧,我這麼做的結果是經常得到一個訪問違例異常“嘗試讀取或寫入受保護的內存,這通常指示其他內存已損壞”,而且我在TextChange裏面設置的try/catch抓不到這個異常。即使不出現異常的時候,我的替換的選項也沒有被顯示出來。”

“等我去倒杯水,我一會來看看你的代碼。”

5分鐘後,程序員甲和程序員乙並肩坐在電腦桌前。程序員乙擡起來,說:“我看不出這段代碼

public AutoCompleteStringCollection GetFilteredList(string prefixText) {

  AutoCompleteStringCollection AutoCol = new AutoCompleteStringCollection();

  Random random = new Random((int)DateTime.Now.Ticks);

for (int i = 0; i < 100; i++) {

    char c1 = (char)random.Next(33, 127);

char c2 = (char)random.Next(33, 127);

char c3 = (char)random.Next(33, 127);

AutoCol.Add(prefixText + c1 + c2 + c3);

}

return AutoCol;

}

private void textBox1_TextChanged(object sender, EventArgs e) {

  //fill autocomplete textbox..

  //SyncRoot-object is not locked at all, so it looks like that is not important

  lock (textBox1.AutoCompleteCustomSource.SyncRoot) {

    textBox1.AutoCompleteCustomSource = GetFilteredList(textBox1.Text);

}

}

有什麼問題。異常是在哪一行拋出來的?讓我看看”

在設置了在拋出異常時中斷之後,程序員乙啓動了Visual Studio調試器。在幾次測試之後,調試器停了下來,報告了一個訪問違例錯誤。

程序員乙馬上打開了調用堆棧窗口,看了看調用歷史,說:“記錄報告異常是在Application.Run這裏拋出的?嗯……拋出異常的好像是Windows內核?”

程序員甲說:“我原先假定Windows是在另一個線程來讀AutoCompleteCustomSource,但是我鎖定AutoCompleteCustomSource的SyncRoot沒有效果。我又沒有辦法改Windows的源代碼,這條路好像行不通。”

程序員乙側頭想了想,說:“不替換AutoCompleteCustomSource,直接用Clear和AddRange修改AutoCompleteCustomSource的內容行不行?”

“好主意,說不定在Windows訪問AutoCompleteCustomSource的時候不能替換這個對象”。

十五分鐘之後,程序員乙擡起頭,說:“嗯,Windows的源代碼不能動,那麼我們就只好試圖創造條件繞過拋出異常的這段代碼了。我想這個訪問越界違例是一個BUG?”

程序員甲搖着頭,說:“MSDN文檔沒有說動態替換AutoCompleteCustomSource是被支持的,也沒有說不支持。”

程序員乙說:“用Refactor看看吧,要是這個功能是.Net基礎類庫的問題的話,你看看是不是可以繞過它自己實現同樣的功能。我記得Internet Explorer裏面就有這個功能,我們應該可以用Internet Explorer的接口。嗯——讓我搜索一下——這裏有一篇文章,說怎麼用IAutoComplete接口實現自動完成功能的。”

十五分鐘之後,程序員甲靠在他的椅子背上說:“從Refactor分析來看,TextBox也是用的同一個接口。只不過AutoCompleteCustomSource實現了IEnumString而已。等等,是不是不能替換IEnumString的實現呢?看起來我需要自己實現IEnumString了。我恨p-invoke……”

程序員乙打斷了他的話:“幹活吧,沒試過你怎麼知道行不行。”

程序員甲開始敲鍵盤。程序員乙一口喝乾了被子裏面的水,起身倒了杯水回自己的座位上去了。

兩個小時之後程序員甲衝到程序員乙的座位旁邊,興高采烈地說:“嘿,我的程序現在沒拋異常了!”

程序員乙迴應:“哦,等我敲完這段代碼——你的IP是多少?登錄到你的機器,我們來看看你怎麼寫的。”

在程序員甲用遠程桌面控制他的機器之後,程序員乙開始掃描程序員甲的代碼。

十分鐘後,程序員乙開口說:“看起來你從替換IEnumString的實現改成了實現替換IEnumString替換它的數據源?”

程序員甲說:“就是這樣。但是在用戶打字的時候動態改變數據源的內容似乎沒有用。IEnumString::Next根本沒有被調用。看起來Windows在輸入第一個字母的時候緩存了提示列表的內容。”

未完待續……

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章