博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编程疑难杂症の莫名的神秘联结
阅读量:5074 次
发布时间:2019-06-12

本文共 5050 字,大约阅读时间需要 16 分钟。

引言:在自己使用Microsoft Visual C# 速成版编程过程中,时不时总出现一些很郁闷的问题,一直尚未得到解决,在此特地列出来,向园里的朋友们求助讨论一番。

注:本人已经Google和百度求助过,但是没有找到满意的答案,当然不排除自己的搜商还不够,假如哪位朋友能帮找出来,那更好!

问题说明:

      最近项目“聊天记录管理器”已经趋于稳定了。绝大部分的功能已经定型并且可用了。

所以接下来的工作基本上就是对代码进行维护,并逐渐完善原有功能。就在这个过程中,就又出现了一个莫名不得其解的问题。详细描述如下:

这次要进行完善的功能是:【自动检测飞信号码】功能。为此已经完整的重构到如下函数中:

///         /// 自动检测短信中是否有飞信聊天记录。        ///         private void YEAutoCheckFeiXin()        {            if ( ckbAutoCheckFeixin.Checked )            {                lstFeiXinBackup.Clear();                //将当前状态备份为一个快照。即不想检测飞信的时候能够恢复原来的数据。                lstFeiXinBackup.AddRange(lsvMessageShower.Items.Cast
()); Debug.Print(lstFeiXinBackup[ 1 ].SubItems[ 1 ].Text);//显示已经被赋值后的lstFeiXinBackup变量里面的第二个元素的值。 foreach ( ListViewItem tmp in lsvMessageShower.Items ) { if ( tmp.SubItems[ 0 ].Text != "sms" ) continue; if ( tmp.SubItems[ 1 ].Text.Contains("12520") ) { tmp.SubItems[ 1 ].Text = tmp.SubItems[ 4 ].Text.Remove(tmp.SubItems[ 4 ].Text.IndexOf(':')); tmp.SubItems[ 4 ].Text = tmp.SubItems[ 4 ].Text.Remove(0 , tmp.SubItems[ 4 ].Text.IndexOf(':') + 1); } else if ( tmp.SubItems[ 2 ].Text.Contains("12520") ) tmp.SubItems[ 2 ].Text = MyNickName.Text;//作为个人网名 else continue; //设置为飞信的时间格式。 tmp.SubItems[ 3 ].Text = tmp.SubItems[ 3 ].Text.Replace('.' , '-'); tmp.SubItems[ 3 ].Text += ":00"; } Debug.Print(lstFeiXinBackup[ 1 ].SubItems[ 1 ].Text);//再次显示该元素的值,用于和第一个显示的值想比较。 } else { if ( lstFeiXinBackup.Count == 0 ) return; lsvMessageShower.Items.Clear(); lsvMessageShower.Items.AddRange(lstFeiXinBackup.ToArray()); //马上初始化此快照。 lstFeiXinBackup.Clear(); } }

这个函数在“自动检测飞信”的复选框按钮的Checked属性更改的时候调用。当勾选此复选框之后,进入检测代码;首先保存一个当前列表框的状态,这里我使用的是泛型List<>来对其进行保存,由于ListView控件本身没有对应函数转换成List可以AddRange的格式,所以这里我使用Cast<Type>来满足这个需求。

代码很成功的把ListView控件中的所有数据保存到了泛型List变量里面了,第一个Debug正确打印出了一个值,是未经修改的手机号码如下格式:12520xxxxxxxxxx;这是飞信的号码段。于是在下面的Foreach循环中不断的检测每一行,把凡是此号码段的都修改为标准的飞信聊天记录格式:(XX网名,时间,聊天内容)。而这个操作呢就是对ListView控件中的发送人1手机号码进行修改为对应网名。

接下来,问题就来咯。在第二个Debug的打印中,发现之前打印的那个元素此刻的值居然也发生了改变。打印出的是在Foreach循环中改变后的值!

症状诊断:

打一出现这个问题,我就想到了一个词“引用类型”。难道问题的源头就是引用类型?!感觉翻看曾经的读书笔记:

果然不出所料。借此机会强化了对泛型List<Type>的印象了。在此引用微软帮助如下:

 

 

性能注意事项:
在决定使用 List<(Of <(T>)>) 还是使用 ArrayList 类(两者具有类似的功能)时,记住 List<(Of <(T>)>) 类在大多数情况下执行得更好并且是类型安全的。如果对 List<(Of <(T>)>) 类的类型 T 使用引用类型,则两个类的行为是完全相同的。但是,如果对类型 T 使用值类型,则需要考虑实现和装箱问题。

 

由此可以推知我使用的ListViewItem类型是引用类型。赶紧查看一下帮助。

暂时没有找到解决方案!

[By:]2010年12月17日 20:43:07

解决方案:

      今天一早起床(呵呵,其实是中午十二点才起的),当自己再次面对昨天的这个问题,思考怎么对付的时候,有了一个不错的想法:既然是在引用类型出了错,那么要解决的问题就是该怎么样实现深度复制(Deep Copy)的功能,负责把ListView控件里面的每一项数据完整而独立的生成一个备份!

      记得昨天在查询ListViewItem类型的MSDN帮助的时候,发现了在它的类声明里,实现了ICloneable借口!意思就是说

列表框的[数据项]本身其实提供了一个Clone方法,貌似可以实现深度复制(Deep Copy)功能。于是赶紧编码测试,修改后代码如下:

///         /// 自动检测短信中是否有飞信聊天记录。        ///         private void YEAutoCheckFeiXin()        {            if ( ckbAutoCheckFeixin.Checked )            {                lstFeiXinBackup.Clear();                foreach ( ListViewItem tmp in lsvMessageShower.Items )                {                    /* 将当前状态备份为一个快照。即不想检测飞信的时候能够恢复原来的数据。                     * 必须使用这里的Clone函数对每一项进行克隆,才能达到深度复制。否则ListViewItem作为引用类型,                     * 使用直接赋值的话,控件里的项更改后,存在lstFeiXinBackup里面的项的值也会更改!*/                    lstFeiXinBackup.Add((ListViewItem)tmp.Clone());                    if ( tmp.SubItems[ 0 ].Text != "sms" )                        continue;                    if ( tmp.SubItems[ 1 ].Text.Contains("12520") )                    {                        tmp.SubItems[ 1 ].Text = tmp.SubItems[ 4 ].Text.Remove(tmp.SubItems[ 4 ].Text.IndexOf(':'));                        tmp.SubItems[ 4 ].Text = tmp.SubItems[ 4 ].Text.Remove(0 , tmp.SubItems[ 4 ].Text.IndexOf(':') + 1);                    }                    else if ( tmp.SubItems[ 2 ].Text.Contains("12520") )                        tmp.SubItems[ 2 ].Text = MyNickName.Text;//作为个人网名                    else                        continue;                    //设置为飞信的时间格式。                    tmp.SubItems[ 3 ].Text = tmp.SubItems[ 3 ].Text.Replace('.' , '-');                    tmp.SubItems[ 3 ].Text += ":00";                }            }            else            {                if ( lstFeiXinBackup.Count == 0 )                    return;                lsvMessageShower.Items.Clear();                lsvMessageShower.Items.AddRange(lstFeiXinBackup.ToArray());                //马上初始化此快照。                lstFeiXinBackup.Clear();            }        }

其实我仅仅修改了一处的代码,那就是把原先直接由ListView控件的Items属性转换而来的数据,改为了在Foreach循环中,一条一条的Clone添加到变量中。

经过测试,完美解决问题

[By:]

2010年12月18日 22:01:40

转载于:https://www.cnblogs.com/AsionTang/archive/2010/12/17/1909560.html

你可能感兴趣的文章
Eclipse 安装SVN插件
查看>>
深度学习
查看>>
TCP粘包问题及解决方案
查看>>
构建之法阅读笔记02
查看>>
添加按钮
查看>>
移动端页面开发适配 rem布局原理
查看>>
Ajax中文乱码问题解决方法(服务器端用servlet)
查看>>
会计电算化常考题目一
查看>>
阿里云服务器CentOS6.9安装Mysql
查看>>
剑指offer系列6:数值的整数次方
查看>>
js 过滤敏感词
查看>>
poj2752 Seek the Name, Seek the Fame
查看>>
软件开发和软件测试,我该如何选择?(蜗牛学院)
查看>>
基本封装方法
查看>>
bcb ole拖拽功能的实现
查看>>
生活大爆炸之何为光速
查看>>
bzoj 2456: mode【瞎搞】
查看>>
[Typescript] Specify Exact Values with TypeScript’s Literal Types
查看>>
[GraphQL] Reuse Query Fields with GraphQL Fragments
查看>>
Illustrated C#学习笔记(一)
查看>>