下午软工实验代码演示,其实说演示不如说是过场,光看结果,又如何知道中间实现的艰辛呢。
先说说此次用到相对以前的区别吧:
1.复习了简单进程的通信,以及windows窗口的检测,详见:进程通信以及活动窗口检测——软件工程实验小记<一>。当然,最后实现的时候,使用了textbox来输入,而不是直接复制ID=45;
2.子窗体都使用了“单例模式”,保证只存在一个实例。当已经存在一个实例的时候,就直接显示那个实例,并使窗口为活动态。
3.子窗体都重载了OnClosing函数,这样,便于管理窗口列表,对进程通信传参提供方便。
4.报表部分,基本复用了 考勤记录提取统计小工具 一文中的excel操作。但是不同的是,这次是用 DataTable 作为数据缓冲区,这样还方便表名的管理。
5.DataGridView右键的管理,并没有直接绑定右键菜单,而是只有在右击某一个单元格时候,才会弹出菜单,并且,自动选取整行。具体实现:
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e) { if (e.Button == MouseButtons.Right) { if (e.RowIndex >= 0) { if (dataGridView1.Rows[e.RowIndex].Selected == false) { dataGridView1.ClearSelection(); dataGridView1.Rows[e.RowIndex].Selected = true; } if (dataGridView1.SelectedRows.Count == 1) { dataGridView1.CurrentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]; } if (dataGridView1.SelectedRows[0].Cells[1].Value == DBNull.Value) { contextMenuStrip1.Items[1].Enabled = false; contextMenuStrip1.Items[0].Enabled = true; } else { contextMenuStrip1.Items[1].Enabled = true; contextMenuStrip1.Items[0].Enabled = false; } contextMenuStrip1.Show(MousePosition.X, MousePosition.Y); } } }
6.使用了线程,知道了线程的2种简单调用方法中,一种不可以带参数,一种带参数只能带一个,且定义为object变量(之后在线程函数内部再拆开)。
开线程操作:
new Thread(allReport).Start(new TIMEBUCKET() {start=dateTimePicker1.Value.Date,end=dateTimePicker2.Value.Date });
allReport内部:
private void allReport(object t) { TIMEBUCKET temp = (TIMEBUCKET)t; if (temp.start.Date > temp.end.Date) { MessageBox.Show("时间错误!"); return; } DataTable dt; if (!getDTforAll(out dt, temp.start, temp.end)) return; saveExcel(dt); }
7.使用了正则来提取数据:(P.S.今天才加上的,不过好在之前对正则有所了解,所以不太难。另外说一句,枚举还是挺好的,现在也习惯于使用枚举变量了。)
private static string opeText(string p, returnInt tag) { switch (tag) { case returnInt.密码字符串: return Regex.Replace(p, @"[^a-z]*", ""); case returnInt.仅数字: return Regex.Replace(p, @"[^\d]*", ""); case returnInt.浮点数: return Regex.Matches(p, @"\d+\.?\d+")[0].Value; default: throw new Exception(); } }
既然说了区别,肯定还有不足:
1.代码整洁度还有待提高。在写代码前,没有很好的规划,都是想到哪写到哪,然后,发现可以复用的函数,再提取出来进行复用。
2.正确率有待提高,写出来的代码,不能保证一次测试通过,且有些错误,真的是很小白的错误。
3.个人知识面涉及不广,有时候,有些知识点也不知道,需要反复找资料,不过,总是在成长的嘛~
4.不喜欢测试,写完一长段代码后,不会立刻去测试,总担心自己错了,然后又得找错误,好烦。
其实还有很多的不足吧,但是,即兴写的,难免有所遗漏。
软工实验给我的感受吧:
在实验中,如果你认真的去学了,还是可以学到很多东西的,了解到很多知道。就拿对于编码的人来说,如果你一次都没做过这样的系统,经过一次这样的实验,至少学会初步使用winform编程了吧。反而对于常用控件都大致知道什么的人,只能说,不停的选择更好的方法去实现代码了吧。还记得当和老师说使用了单例模式的时候,老师笑了,或许是笑居然还知道单例模式吧,但是,我想说,我用的还是简简单单的一个单例模式吧,都没有互斥锁什么的。
老师课上说过好几次,80%的错误,出在了20%的代码中。现实编程中,我确实是如此的。犯的最多的地方就是sql连接的变量忘记new了,每次都是在try-catch外部default()后,在内部就忘记new,导致报错,然后中断测试。第二错的地方,就是sql语句的写法,也犯了好几次。。。。比较无语的是delect写错了。然后还有,在使用参数化查询的时候,指定类别错误,然后导致总是查不到用户,但是又不知道在哪错了,最后发觉是 SqlDbType.BigInt 写成了SqlDbType.Bit。导致参数化查询错误。
然后,或许所有的错误加起来都没下午犯的错误最大吧。如下的代码:
if (mysql.sqlExecution("INSERT INTO [User] (uID,uName,uLevel,uRemain,uStatus,uPassword,uComment) VALUES (@uID,@uName,@uLevel,@uRemain,@uStatus,@uPassword,@uComment)") ==0
) MessageBox.Show("卡号已存在"); else MessageBox.Show("注册成功");
这样的代码,或许以人的逻辑正确,如果Insert语句影响的行数为0,说明没有插入成功,那么说明卡号已经存在了。但是下午就是这样一个错误,导致同学的丢脸了。实际上,这一部分,应该是如果存在相同键,则会抛出异常。然后,什么提示都没有了(但是catch段函数生成了错误日志)。 所以,在插入数据之前应该先判断是否存在该卡号,然后再插入。
但是现场却发生了这样的错误。这一部分是最早写的部分,由于上述不足中的4,我没有进行完整的测试,只测试了正常的状况,而没有测试重复的问题。好吧,很对不起某人,尤其在老师说的:一看就是很少调程序的人。老师这个时候应该已经怀疑了,而这个时候,C也是尴尬的吧,哎。真心对不起啊,好心办了坏事吧。想到一句歌词:既然是兄弟,这一种关系,绝不做合伙生意。---《你是我兄弟》歌词。
最后的小结:
以后写代码,必须进行完整的测试,一方面是对程序负责,也是对自己负责。绝不允许不做测试就发布的情况,ZQY!
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>