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单子以后,简单重现了下,基本上定位到是查询操作中的问题, ...
随机推荐
- C#语句1:选择语句二(switch break)
(二)switch case switch case 必须与 break 一同使用.break是跳转语句.与switch case连用的时候是跳出最近的{}. 注: ●若case后面接收的是字符串类型 ...
- SQL Server 2000:提示“未与信任SQL SERVER连接相关连”错误
在使用“用户模式”登陆SQL Server 2000时提示“未与信任SQL SERVER连接相关连”错误,因为在安装SQL Server时选择“仅Windows”模式,所以所有用户都不可以登陆. 解决 ...
- Servlet/JSP-02 Servlet相关类
ServletConfig / ServletContext / ServletRequest / ServletResponse 一. ServletConfig:封装了Servlet得配置信息,并 ...
- mysql学习笔记(一)
my建表操作 创建表 create Table <表名> ( 字段名1,数据类型 [列级约束] [默认值], 字段名2,数据类型 [列级约束] [默认值], ... [表级约束], [co ...
- 安装DELL R430服务器的过程记录
序: 本次需要安装一个ineedle设备给客户用,貌似客户是华三.这次领导比较重视,下血本买了一台DELL服务器,似乎花费了1万多大洋.当然配置是比较高了,CPU:Intel(R) Xeon(R) C ...
- 禁止用户选定文本: user-select
双击文本 select,会被选定,如下 但有时点击元素时不想要被选定的状态,有一个尚未成为标准的 CSS 属性: user-select,它有 4 个值: text 可以选择文本 element 可以 ...
- linux vi编辑器操作手册
简介 Linux下的文本编辑器有很多种,vi 是最常用的,也是各版本Linux的标配.注意,vi 仅仅是一个文本编辑器,可以给字符着色,可以自动补全,但是不像 Windows 下的 word 有排版功 ...
- linux挂载windows上的共享文件夹
假定win机d:/folder/share的共享名为 share , 有用户administrator ,密码123 在linux机上,把share挂到/mnt目录:mount -t cifs -o ...
- Objective-C if语句处理 BOOL值不为1和0的情况
BOOL ,布尔值,在Objective-C ,BOOL类型被typedef为signed char(有符号的整型),YES被#define为1,NO被#define为0. 事实上,xcode的编译器 ...
- hdu2896 病毒侵袭 ac自动机
地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=2896 题目: 病毒侵袭 Time Limit: 2000/1000 MS (Java/Othe ...