关闭

关于自动完成功能的一段会话

标签: textboxwindowsautocompleterandominternet数据库
9226人阅读 评论(13) 收藏 举报
分类:

已经是下午三点了。太阳已经不再直射软件开发部的窗户。在窗前的电脑桌边,程序员甲斜靠在他的真皮靠背椅上,瞪着天花板。

“怎么了?”去饮水机倒水路过程序员甲背后的程序员乙说:“你又卡住了?”

“是啊!”程序员甲叹了口气,说:“那个该死的自动完成功能问题太多。”他深呼吸了一下,甩甩头说:“再搞不出来我就得和老板谈谈是不是要取消这个功能了。”

“你设置了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在输入第一个字母的时候缓存了提示列表的内容。”

未完待续……

 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:723695次
    • 积分:7663
    • 等级:
    • 排名:第2915名
    • 原创:108篇
    • 转载:3篇
    • 译文:0篇
    • 评论:334条
    最新评论
    Google Profile
    知识的泉源