Enum引发的血案,反思

前几天公司产品更新版本,更新完后不少用户反应原先保存的report的一些表在新版本打开后设置突然变了,本来选的第六个,现在打开变成第四个了。领导要求赶紧查出原因修改好,发紧急补丁。啊啊。。发紧急补丁可是影响team的performance的,年终奖要打折扣了。。

问题是很容易就查到了,那些设置是用Enum表示的,如下:

 1 public enum PeergroupRanks
 2 {
 3     VSBenchmark,
 4     VSBenchmark2,
 5     CalBenchmark,
 6     PeersBeaten,
 7     NumPeergroupBeaten,
 8     PeergroupRank,
 9     NumPeergrouprank,
10     PeergroupPercentile,
11     PeergroupDecile,
12     PeergroupQuintile,
13     PeergroupQuartile,
14 
15     PeergroupRankOfCount,
16 }

一位同事做新feature时加了上面红色的两个,由于存report的时候对于这个Enum只是简单的转成int存起来,大家都知道Enum默认是从0开始,按顺序来,原先存的第6个是PeergroupPercentile,report里存的就是数字5,新加了两个在上面后,数字5就解析成PeergroupRank了。

分析这个问题,觉得这个应该算是代码本身有漏洞,同事不小心踩到了,因为这位同事想法也不能说错,把同一个类型的放到一起,都是Benchmark,代码可读性强。

其实项目里大部分代码对Enum是有所防范的,如:

 1 public enum DisplayBenchmark
 2 {
 3     None,
 4     Benchmark1,
 5     Benchmark2,
 6     CategoryAverage,
 7     CalcBenchmarkId,
 8     CalcBenchmarkType,
 9     CalcBenchmarkCdp,
10 }
11 
12 public static class DisplayBenchmarkCode
13 {
14     const string BENCHMARK1 = "bm1";
15     const string BENCHMARK2 = "bm2";
16     const string CATEGORY = "ca";
17 
18     public static DisplayBenchmark Parse(string code)
19     {
20         switch (code)
21         {
22             case BENCHMARK1:
23                 return DisplayBenchmark.Benchmark1;
24             case BENCHMARK2:
25                 return DisplayBenchmark.Benchmark2;
26             case CATEGORY:
27                 return DisplayBenchmark.CategoryAverage;
28         }
29         return DisplayBenchmark.Benchmark1;
30     }
31 
32     public static string Convert(this DisplayBenchmark type)
33     {
34         switch (type)
35         {
36             case DisplayBenchmark.Benchmark1:
37                 return BENCHMARK1;
38             case DisplayBenchmark.Benchmark2:
39                 return BENCHMARK2;
40             case DisplayBenchmark.CategoryAverage:
41                 return CATEGORY;
42         }
43         return BENCHMARK1;
44     }
45 }

在report里存的是DsiplayBenchmarkType.Convert成的字符串,解析时再Parse,这样更安全,增加Type的同时也要增加相应的Code,一一对应。

当然,在Enum里写上具体值也是可行的,如:

1 public enum PeergroupRanks
2 {
3     VSBenchmark=0,
4     VSBenchmark2=1,
5     CalBenchmark=2,
6     PeersBeaten=3,
7 }

还有人觉得直接用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风格也会积极影响所有成员。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏知识分享

1-关于单片机通信数据传输(中断发送,大小端,IEEE754浮点型格式,共用体,空闲中断,环形队列)

写这篇文章的目的呢,如题目所言,我承认自己是一个程序猿.....应该说很多很多学单片机的对于...先不说别的了,,无论是学51的还是32的,,,先问一下大家用串...

2645
来自专栏Windows Community

Windows Community Toolkit 3.0 - Gaze Interaction

Gaze Input & Tracking - 也就是视觉输入和跟踪,是一种和鼠标/触摸屏输入非常不一样的交互方式,利用人类眼球的识别和眼球方向角度的跟踪,来判...

1213
来自专栏犀利豆的技术空间

Java 渲染 docx 文件,并生成 pdf 加水印

一顿google以后发现了 StackOverflow 上的这个回答:Converting docx into pdf in java 使用如下的 jar 包:

2001
来自专栏开发 & 算法杂谈

基于Lockset的数据竞争检测方法汇总(一)

对于搞数据竞争检测方向的人来说,Lockset方法大家肯定不陌生,作为一个刚入门数据竞争检测方向的我来说,就和大家总结一下我近期有关Lockset方法的一些研究...

1654
来自专栏NetCore

[原创]Fluent NHibernate之旅二--Entity Mapping

接着上一篇,今天我们说说ORM中的Mapping。如果你要体验NHibernate的强大,首先你就要学会配置,包括SessionFactory和Mapping的...

2149
来自专栏数说工作室

【SAS Says】基础篇:7. SAS宏初步

宏用来处理重复工作最好,比如你需要跑10个回归,用proc reg...,这10个回归其他都一样,就是因变量y每次需要换。那么将回归程序写成一个宏,每次用的时候...

3716
来自专栏数说工作室

【SAS Says】基础篇:SAS宏初步

特别说明:本节【SAS Says】基础篇:SAS宏初步,用的是数说君学习《The little SAS book》时的中文笔记,我们认为这是打基础的最好选择。 ...

2954
来自专栏张善友的专栏

使用Metrics.NET 构建 ASP.NET MVC 应用程序的性能指标

通常我们需要监测ASP.NET MVC 或 Web API 的应用程序的性能时,通常采用的是自定义性能计数器,性能计数器会引发无休止的运维问题(损坏的计数器、权...

1958
来自专栏北京马哥教育

shell十三问,为linux学习打基础(一)

本文整理并转自CU上的帖子[学习共享] shell 十三問?,此贴是2003年发表的,但却是相当不错的linux基础知识汇集贴,原帖主使用的台湾风格,本文加以简...

3514
来自专栏京东技术

Sieve—Android 内存分析系统 | 解决你的内存溢出问题

内存问题是个老大难,对用户来说,泄漏或者不合理的内存使用最终会反映到性能和体验上,并且极易造成 OOM( Out Of Memories ) 而闪退, 而对开发...

1452

扫码关注云+社区