Enum引发的血案,反思
前几天公司产品更新版本,更新完后不少用户反应原先保存的report的一些表在新版本打开后设置突然变了,本来选的第六个,现在打开变成第四个了。领导要求赶紧查出原因修改好,发紧急补丁。啊啊。。发紧急补丁可是影响team的performance的,年终奖要打折扣了。。
问题是很容易就查到了,那些设置是用Enum表示的,如下:
public enum PeergroupRanks
{
VSBenchmark,
VSBenchmark2,
CalBenchmark,
PeersBeaten,
NumPeergroupBeaten,
PeergroupRank,
NumPeergrouprank,
PeergroupPercentile,
PeergroupDecile,
PeergroupQuintile,
PeergroupQuartile, PeergroupRankOfCount,
}
一位同事做新feature时加了上面红色的两个,由于存report的时候对于这个Enum只是简单的转成int存起来,大家都知道Enum默认是从0开始,按顺序来,原先存的第6个是PeergroupPercentile,report里存的就是数字5,新加了两个在上面后,数字5就解析成PeergroupRank了。
分析这个问题,觉得这个应该算是代码本身有漏洞,同事不小心踩到了,因为这位同事想法也不能说错,把同一个类型的放到一起,都是Benchmark,代码可读性强。
其实项目里大部分代码对Enum是有所防范的,如:
public enum DisplayBenchmark
{
None,
Benchmark1,
Benchmark2,
CategoryAverage,
CalcBenchmarkId,
CalcBenchmarkType,
CalcBenchmarkCdp,
} public static class DisplayBenchmarkCode
{
const string BENCHMARK1 = "bm1";
const string BENCHMARK2 = "bm2";
const string CATEGORY = "ca"; public static DisplayBenchmark Parse(string code)
{
switch (code)
{
case BENCHMARK1:
return DisplayBenchmark.Benchmark1;
case BENCHMARK2:
return DisplayBenchmark.Benchmark2;
case CATEGORY:
return DisplayBenchmark.CategoryAverage;
}
return DisplayBenchmark.Benchmark1;
} public static string Convert(this DisplayBenchmark type)
{
switch (type)
{
case DisplayBenchmark.Benchmark1:
return BENCHMARK1;
case DisplayBenchmark.Benchmark2:
return BENCHMARK2;
case DisplayBenchmark.CategoryAverage:
return CATEGORY;
}
return BENCHMARK1;
}
}
在report里存的是DsiplayBenchmarkType.Convert成的字符串,解析时再Parse,这样更安全,增加Type的同时也要增加相应的Code,一一对应。
当然,在Enum里写上具体值也是可行的,如:
public enum PeergroupRanks
{
VSBenchmark=,
VSBenchmark2=,
CalBenchmark=,
PeersBeaten=,
}
还有人觉得直接用const string就好,个人以为Enum的强类型还是比string好,string的可能性比较多,直接用字符串比较也行,用其他同样string的变量比较也行,没有唯一性,而Enum只能是相同的Type进行比较。
类似的问题的还有hashcode,hashcode会不会变也是依赖于.net framework的算法,谁也不能保证以后算法不会变,所以hashcode也不要做为key存起来,否则后期要改会变得很困难,因为还需要兼容以前存的档案。
另外多语言下的数字也是值得注意的,欧洲那边很多国家的小数点是用逗号表示,分隔符用点号,和我们正好相反,如: 123.456,78 ,这种情况就需要以固定格式存下来,比如ToString时用CultureInfo.InvariantCulture,这样跟区域语言无关,解析时也一样是固定格式解析,double.Parse(value, CultureInfo.InvariantCulture)。显示在界面时就需要用当前的语言格式来显示,总不能给西班牙人看我们常用的小数格式,CultureInfo.CurrentCulture这是当前线程的语言格式,用这个就可以了。
总结起来,要持久化存起来并且需要解析还原的东西是不能变的,保存前是什么状态解析后也要还原这个状态,所以Enum一定要写上值或做转换再存,同样还有hashcode,情愿存长一些的字符串也不要存hashcode(自定义的算法无所谓哈),多语言应用下的小数也需要注意保存和显示的区别。
然后就是上面看到的,同样的项目中绝大部分Enum都做了防范,小部分因为代码规范问题,没能保持一致才出了问题,所以个人觉得这些问题属于基本代码规范问题,在项目设计时就决定好了,每个人不管是老同事还是新进来的同事都需要遵守规范,这样的项目代码更安全,可持续性也更好。
规范的目标是让项目的代码看起来像是一个人写的,团队好的coding风格也会积极影响所有成员。
Enum引发的血案,反思的更多相关文章
- [WCF]缺少一行代码引发的血案
这是今天作项目支持的发现的一个关于WCF的问题,虽然最终我只是添加了一行代码就解决了这个问题,但是整个纠错过程是痛苦的,甚至最终发现这个问题都具有偶然性.具体来说,这是一个关于如何自动为服务接口(契约 ...
- dubbox微服务实例及引发的“血案”
Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成. 主要核心部件: Remoting: 网络通信框架 ...
- Integer.parseInt 引发的血案
Integer.parseInt 处理一个空字符串, 结果出错了, 程序没有注意到,搞了很久, 引发了血案啊!! 最后,终于 观察到了, 最后的部分: Caused by: java.lang.NoC ...
- Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)
<Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Repli ...
- Replication的犄角旮旯(七)-- 一个DDL引发的血案(下)(聊聊logreader的延迟)
<Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Repli ...
- 转:一个Sqrt函数引发的血案
转自:http://www.cnblogs.com/pkuoliver/archive/2010/10/06/1844725.html 源码下载地址:http://diducoder.com/sotr ...
- 一个Sqrt函数引发的血案(转)
作者: 码农1946 来源: 博客园 发布时间: 2013-10-09 11:37 阅读: 4556 次 推荐: 41 原文链接 [收藏] 好吧,我承认我标题党了,不过既然你来了, ...
- 一个字母引发的血案 java.io.File中mkdir()和mkdirs()
一个字母引发的血案 明天开始放年假了,临放假前有个爬虫的任务,其中需要把网络图片保存到本地,很简单,马上写完了代码: //省略部分代码... Long fileId= (Long) data.get( ...
- form表单提交引发的血案
最近,公司某条产品线上的一个功能出了问题:点击查询的时候,该页面在IE上直接卡死,chrome上会卡顿一段时间候提交表单进行查询.拿到这个bug单子以后,简单重现了下,基本上定位到是查询操作中的问题, ...
随机推荐
- ADO.Net(四)——扩展属性和配置文件应用
一.扩展属性 处理:有外键关系时将代号化信息处理成原始文字,让用户可看懂的(粗略解释) 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展 ...
- The Accidental DBA
The Accidental DBA (Day 1 of 30): Hardware Selection: CPU and Memory Considerations 本文大意: 全篇主要讲 ...
- MySQL 系列(五) 多实例、高可用生产环境实战
MySQL 系列(五) 多实例.高可用生产环境实战 第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 史上最屌.你不知道的数据库操作 第三 ...
- eclipse插件Maven添加依赖查询无结果的解决方法(Select Dependency doesn't work)
在eclipse中用过maven的可能都遇到过这种情况,我以前一直在search.maven里面搜索,然后添加pom信息. 今天在网上搜索时,找到了一个解决方法,在这里分享一下. 第一步,在prefe ...
- HTTP状态码206和416
HTTP 2xx范围内的状态码表明了:"客户端发送的请求已经被服务器接受并且被成功处理了". TTP/1.1 200 OK是HTTP请求成功后的标准响应 HTTP/1.1 206状 ...
- VIM使用技巧总结
一.vim使用的基本配置 1: set nu //设置行号 2: set ts=4 //设置tab为4个空格大小 3: set expandtab //设置用空格代替tab 4: set ai //设 ...
- 绕过校园网的共享限制 win10搭建VPN服务器实现--从入门到放弃
一.开篇立论= =.. 上次说到博主在电脑上搭建了代理服务器来绕过天翼客户端的共享限制,然而经过实际测试还不够完美,所以本着生命不息,折腾不止的精神,我又开始研究搭建vpn服务器= =... (上次的 ...
- android switch(String)错误:Cannot switch on a value of type String for source level below 1.7
switch语句的判断条件可以接受int,byte,char,short,不能接受其他类型只有JDK版本1.7以上才可以支持String 设置如下可解决问题:(若没有JDK1.7版,可下载一下安装)菜 ...
- Centos和Redhat的区别和联系
网上看到的,转载给大家 CentOS与RedHat的关系: RedHat在发行的时候,有两种方式:二进制的发行方式以及源代码的发行方式.无论是哪一种发行方式,你都可以免费获得(例如从网上下载),并再次 ...
- linux shell 之 crontab(定时任务)详解
1.定义: crontab命令常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行.该词来源于希 ...