分类: C/C++
2008-08-01 17:02:21
摘要 本文讲述了本人在编写一个IP:Port提取器过程中发现 Bug 并最终排除它们的过程,并解释了原理。
关键字 VC# 正则表达式 调试
我最近在看正则表达式,加之本人又是一个 CSer,于是想着利用正则表达式从文件中提取 IP:Port
这样的服务器地址,于是便有了昨天写的这个项目(不要被它的项目名称迷惑,我本来要做个关机程序 Shutdown 的,后来才改做这个
IPPortAbstractor 的)。先看看它的界面吧。
接着我完成了最初的代码,在调试过程中发现了以下几个Bug:
1、ProcessMatch() 成员中:
Bug-1:下面这样并不会引发编译错误,但是 StringBuilder 数组的数据元素需要另行 new
,因此在运行时会触发异常“源数组中至少有一个元素无法被向下转换到目标数组类型。”我想我是把 string 与 StringBuilder
看得太简单了。
textlineList.CopyTo(strArray);
正确的做法是利用循环,如下:
for (int i = 0; i< textlineList.Count; i) strArray[i] = new StringBuilder((string) textlineList[i]);
Bug-2:这样也不会引发编译错误,但会触发异常“指定的转换无效。”我看上面的转换都成功了,这里为什么就不行呢?不得其解,还请各位解释一下
matches = m_regexIPPort.Matches((string)textlineList[i]);
正确的做法是利用 object.ToString() 函数,如下:
matches = m_regexIPPort.Matches(textlineList[i].ToString());
2、buttonDelete_Click() 成员中
Bug-3:在这里,我想把用户在 Listbox 中的选中行删除,最先用的是这样的 for 循环,结果会发生无法一次性将多个选中行删除的现象
for (int i = 0; i < listboxResult.SelectedIndices.Count; i) { m_IPPortList.Remove(listboxResult.SelectedItems[i].ToString()); listboxResult.Items.Remove(listboxResult.SelectedItems[i]); }正确的做法如下,这也是我想到的最简单的办法了。 Bug 的产生原因在于 SelectedIndices.Count 在 Remove 操作后会发生变化,从而导致 i 的值发生变化,因此不能使用 for 循环。
while ((i = listboxResult.SelectedIndices.Count) > 0) { // 切记:下面两条语句顺序不能颠倒 // listboxResult.Items.Remove 删除元素后将导致 m_IPPortList.Remove // 无法定位,也会触发异常“索引超出了数组界限。” m_IPPortList.Remove(listboxResult.SelectedItems[i-1].ToString()); listboxResult.Items.Remove(listboxResult.SelectedItems[i-1]); }3、保存搜索结果时一系列的 Bug
if (!IsSaved) { result = MessageBox.Show("搜索结果还没有保存,是否进行保存?", "保存搜索结果", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); switch (result) { case DialogResult.Yes: //要保存 buttonSaveResult_Click(sender, e); Close(); break; case DialogResult.No: //不保存 Close(); break; case DialogResult.Cancel: //返回程序,暂不退出 break; default: break; } }结果当你点击窗口右上角的关闭按钮时没有提示,直接就退出了。于是我为 Form 生成了 Closing 事件的处理函数:
private void IPPortForm_Closing(object sender, System.ComponentModel.CancelEventArgs e) { buttonExit_Click(sender, e); }这下退出时提示倒是有了,但是点击“取消”之后程序也退出了,而没有返回程序。于是把 buttonExit_Click() 的内容删除其中的 Close() 调用后放在 IPPortForm_Closing() 中,而在 buttonExit_Click() 中则调用 Close() 成员。
e.Cancel = true; break;这下解决了点击保存提示对话框的“取消”程序退出的问题,但还是没有解决第一个问题:在点击保存提示对话框的“是”之后,再点击保存文件对话框的“取消”,程序还是直接退出了!想到这里,应该是保存对话框的返回值没有相应的判断,于是给 buttonSaveResult_Click() 添加了一个 else 分支:
else ((CancelEventArgs)e).Cancel = true;问题得到解决了,但又发现了另一个 Bug :点击“保存结果”按钮时在弹出的保存文件对话框中点击“取消”时,程序在上面这条语句处触发异常“指定的转换无效。”另一方面,如果是点击“退出”按钮来弹出这个保存文件对话框则不会触发这样的异常,想来想去,只有在程序关闭事件中设置一个标志 IsClosing (初始化为 false )了,于是 buttonSaveResult_Click() 的 else 分支改成了这样:
else ((CancelEventArgs)e).Cancel = true;IPPortForm_Closing()的 case DialogResult.Yes 分支代码改成了这样:
else { if (IsClosing) ((CancelEventArgs)e).Cancel = true; }IPPortForm_Closing()的case DialogResult.Yes分支代码改成了这样:
IsClosing = true; buttonSaveResult_Click(sender, e); break;终于,我的这个 VC# 工程算是完成了。当然我没有使用 try-catch 语句块对可能的空间不足等异常进行处理。不过程序的功能上应该没有 Bug 了吧。希望大家也帮我找找。先打 CS 去了,菜鸟我的 ID: TANK---Bug 。如果遇到我千万别打我,请让我打死你吧!