Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1568818
  • 博文数量: 884
  • 博客积分: 52280
  • 博客等级: 大将
  • 技术积分: 13060
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-06 09:46
文章分类

全部博文(884)

文章存档

2008年(884)

我的朋友

分类: C/C++

2008-08-06 09:57:13

下载本文示例代码

源代码下载:IPPortAbstractor.rar(8KB)


摘要 本文讲述了本人在编写一个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
  这里连续的 Bug 是项目中我最头疼的。本想在点击“退出”后弹出对话框,提示用户保存搜索结果。选择“是”进行保存,选择“否”直接退出,选择“取消”返回程序。最早 buttonExit_Click() 主要内容是这样的:
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() 成员。
  之后发生的事就更好玩儿了:在保存结果时如果点击保存文件对话框的“取消”按钮,程序直接退出!点击保存提示对话框的“取消”程序也直接退出。这下真的头疼了!寻寻觅觅,终于让我发现 System.ComponentModel.CancelEventArgs 变量 e 中一个属性 Cancel 可用,设置其为 true 将导致该事件被取消,于是我把 case DialogResult.Cancel 分支改成这样:
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 。如果遇到我千万别打我,请让我打死你吧!

下载本文示例代码
阅读(235) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~