继续说一说昨天提到的那个代码重构

简介:
昨天我给了一段.NET Framework 2.0中的 一段代码,希望大家能重构一下。结果大家没有对代码本身提出什么积极的看法,倒是有几位热心人代码都没有看清,就大肆予以评论 what_smile.gif(因为那段代码是错的,现已修正)。下面再说一下这段代码的特点和问题,欢迎有兴趣并能看到诗的博友斧正。

    还是说一下代码的来源,这段代码确实是使用Reflector反编译出来的,不过从代码的优化痕迹来看,是比较忠实于最初的源代码的。另一个反证是新的源代码编译后再反编译,结果仍是很相近。上次给出的那段 代码,一眼看上去确实是挺让人郁闷的,正如 robaggio同学搞笑的说:也许是某种inline机制吧。。。 

    而仔细看昨天那段代码,除了行数多外,从效率上来说基本已是无懈可击。这么说有什么依据,凭什么说这个代码很优化?那么我们来看一下.NET Framework 1.1中QuoteJScriptString(string)方法的实现:
None.gif public  static  string QuoteJScriptString( string value)
ExpandedBlockStart.gif ContractedBlock.gif dot.gif{
InBlock.gif    StringBuilder strbQuoted =  new StringBuilder(value.Length + 5);
InBlock.gif     for (  int i = 0; i < value.Length; i++)
ExpandedSubBlockStart.gif ContractedSubBlock.gif     dot.gif{
InBlock.gif         char ch = value[i];
InBlock.gif         if (ch <= '"')
ExpandedSubBlockStart.gif ContractedSubBlock.gif         dot.gif{
InBlock.gif             switch(ch)
ExpandedSubBlockStart.gif ContractedSubBlock.gif             dot.gif{
InBlock.gif                 case '\t':
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted.Append(@"\t");
InBlock.gif                     continue;
ExpandedSubBlockEnd.gif                }
InBlock.gif                 case '\n':
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted.Append(@"\n");
InBlock.gif                     continue;
ExpandedSubBlockEnd.gif                }
InBlock.gif                 case '\v':
InBlock.gif                 case '\f':
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted.Append(value[i]);
InBlock.gif                     continue;
ExpandedSubBlockEnd.gif                }
InBlock.gif                 case '\r':
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted.Append(@"\r");
InBlock.gif                     continue;
ExpandedSubBlockEnd.gif                }
InBlock.gif                 case '"':
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted.Append("\\\"");
InBlock.gif                     continue;
ExpandedSubBlockEnd.gif                }
ExpandedSubBlockEnd.gif            }
ExpandedSubBlockEnd.gif        }
InBlock.gif         else
ExpandedSubBlockStart.gif ContractedSubBlock.gif         dot.gif{
InBlock.gif             if (ch == '\'')
ExpandedSubBlockStart.gif ContractedSubBlock.gif             dot.gif{
InBlock.gif                strbQuoted.Append(@"\'");
InBlock.gif                 continue;
ExpandedSubBlockEnd.gif            }
InBlock.gif             if (ch == '\\')
ExpandedSubBlockStart.gif ContractedSubBlock.gif             dot.gif{
InBlock.gif                strbQuoted.Append(@"\\");
InBlock.gif                 continue;
ExpandedSubBlockEnd.gif            }
ExpandedSubBlockEnd.gif        }
InBlock.gif        strbQuoted.Append(value[i]);
ExpandedSubBlockEnd.gif    }
InBlock.gif     return strbQuoted.ToString();
ExpandedBlockEnd.gif}

    要想知道自己写的代码是否是业余水平,我认为可以参考一下上面这段代码 emembarrassed.gif。这段代码我觉得唯一有意义的地方就是创建StringBuilder对象的时候,给出了Capacity的大小,而且也仅此这一点显得和业余水平之间有了一点点的差距。至于为什么判断ch <= ' "',我没有太明白,是因为swith中case太多会有什么效率问题吗?虽然' "'是ASCII中顺序里的第二个可打印字符(不算Space),但是这样将ch的检测路径分开,我没有觉得有什么大的意义。

    那么2.0中的QuoteJScriptString有什么特点呢?一是:修改了bug,给QuoteJScriptString添加了一个forUrl的bool参数,指示转换时是否转换"%"为其escape(JScript中的全局函数)形式。因为如果当你把脚本代码使用到link的href中时,IE会自动的unescape这个字符串,再作为代码解析执行。看下面的示例:
None.gif < href ="JavaScript: alert('%25%');" >click </ a >

    如果在IE中你点击了click后,你觉得MsgBox里会显示啥?是"%25%"吗?实际上显示的是:"%%"。这就是为什么新版的方法要添加forUrl开关参数的原因,是为了修复bug。二是:优化了QuoteJScriptString方法的效率,除了继续沿用了创建StringBuilder那个地方外,还有三点。1) 做了参数合法性检查;2) 消除了不必要的StringBuilder实例的创建;3) 对于不用替换的字符,使用区段处理代替了逐字处理。

    既然都说昨天那段挺不错了,那么还重构个头啊?其实重构只是一个镢头了 emteeth.gif。至于考证代码是不是微软原版的,我只能说:别人看到了诗 emnote.gif,有的人看到屎 bb.gif。真的要重构,也就主要是节省点代码了,我相信程序员都是很懒的,即使打字再快,毕竟我们也不是打字员哈。给一个重构后的版本,代码如下:
None.gif public  static  string QuoteJScript( string value,  bool forUrl)
ExpandedBlockStart.gif ContractedBlock.gif dot.gif{
InBlock.gif     if (StringHelper.IsEmpty(value))
ExpandedSubBlockStart.gif ContractedSubBlock.gif     dot.gif{
InBlock.gif         return  string.Empty;
ExpandedSubBlockEnd.gif    }
InBlock.gif    StringBuilder strbQuoted =  null;
InBlock.gif     int i, position;
InBlock.gif    i = position = 0;
InBlock.gif     const  string QUOTED_CHARS= "\t\n\v\f\r\"%'\\";
InBlock.gif     string  [] QUOTED_STRINGS = 
ExpandedSubBlockStart.gif ContractedSubBlock.gif         dot.gif{ @"\t", @"\n", @"\v", @"\f", @"\r", @"\""", @"%25", @"\'", @"\\" };
InBlock.gif     for ( ; i < value.Length; i++)
ExpandedSubBlockStart.gif ContractedSubBlock.gif     dot.gif{
InBlock.gif         char ch = value[i];
InBlock.gif         int index = QUOTED_CHARS.IndexOf(ch);
InBlock.gif         if ( index >= 0 )
ExpandedSubBlockStart.gif ContractedSubBlock.gif         dot.gif{
InBlock.gif             if ( ch != '%' || ( ch == '%' && forUrl ) )
ExpandedSubBlockStart.gif ContractedSubBlock.gif             dot.gif{
InBlock.gif                 if ( strbQuoted ==  null )
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted =  new StringBuilder(value.Length + 5);
ExpandedSubBlockEnd.gif                }
InBlock.gif                 if ( i-position >= 1 )
ExpandedSubBlockStart.gif ContractedSubBlock.gif                 dot.gif{
InBlock.gif                    strbQuoted.Append(value, position, i-position);
ExpandedSubBlockEnd.gif                }
InBlock.gif                strbQuoted.Append(QUOTED_STRINGS[index]);
InBlock.gif                position = i + 1;
ExpandedSubBlockEnd.gif            }
ExpandedSubBlockEnd.gif        }
ExpandedSubBlockEnd.gif    }
InBlock.gif     if (strbQuoted ==  null)
ExpandedSubBlockStart.gif ContractedSubBlock.gif     dot.gif{
InBlock.gif         return value;
ExpandedSubBlockEnd.gif    }
InBlock.gif     if ( i-position >= 1 )
ExpandedSubBlockStart.gif ContractedSubBlock.gif     dot.gif{
InBlock.gif        strbQuoted.Append(value, position, i-position);
ExpandedSubBlockEnd.gif    }
InBlock.gif     return strbQuoted.ToString();
ExpandedBlockEnd.gif}

    最后有一个有趣的问题,你认为Fx 1.1和2.0中两个QuoteJScriptString是同一个人写的吗?你觉得这种重构方式好不好?是你会怎么做呢?


本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。

目录
相关文章
|
4月前
|
程序员 测试技术
程序员的“Bug之旅”:为何无法一次性写出完美代码?
程序员在软件开发过程中难以一次性写出完美代码,需要不断修改和调试,即“改Bug”,这是由多个因素共同作用的结果。技术层面的复杂性、管理和流程上的不足以及个人能力和认知的局限性都是导致这一现象的重要原因。然而,这并不意味着无法避免或改进。通过加强需求管理、建立有效的版本控制和测试机制、推动团队知识共享以及鼓励代码审查和自我反思等措施,可以降低改Bug的频率和成本,提高软件开发的效率和质量。辩证地看待这一问题,既要理解其存在的合理性,也要积极寻求改进之道,以实现更好的产品和服务。
36 2
答知识星球朋友疑问:执行 ABAP 代码出现超时的原因,背后的理论和解决方案试读版
答知识星球朋友疑问:执行 ABAP 代码出现超时的原因,背后的理论和解决方案试读版
|
机器学习/深度学习 移动开发 前端开发
想加入大厂?看这篇文章也许会帮助到你
相信加入互联网大厂是每个程序员梦寐以求的事情,无论是从工作环境、员工福利,或者说是技术氛围以及接触到的人所给你带来的一些好的机遇,都是值得我们去追求的,因此程序员可以在职业生涯初期、或者在整个职业生涯中加入过大厂,无论对自己的履历还是阅历都是很有帮助的一件事。
97 0
想加入大厂?看这篇文章也许会帮助到你
|
消息中间件 JavaScript 小程序
用1个月重构了同事写的烂代码,我总结出了15条重写烂代码的经验!
用1个月重构了同事写的烂代码,我总结出了15条重写烂代码的经验!
|
数据库
高质量代码优化!谈谈重构项目中if-else代码的几点建议
本篇文章探讨了代码的重构以及优化,主要针对代码中大量的条件判断if-else语句问题提出了具体的优化建议。介绍了优化if-else语句的几种有效的方法,包括switch,接口interface以及数据库实现对条件语句进行的优化。
160 0
高质量代码优化!谈谈重构项目中if-else代码的几点建议
|
新零售 移动开发 人工智能
程序员写好技术文章的几点小技巧
去年成为了内网技术分享平台的年度作者,受邀写一篇关于“如何写好文章”的文章。我本身并不喜欢写字,去年写的几篇文章,涉及的话题自带流量,所以阅读量多了一些,谈不上有多擅长。不过还是决定分享一下自己在写文章时用到的一些小技巧,希望对大家有帮助。
程序员写好技术文章的几点小技巧
|
大数据
【观点】如何写出无法维护的代码
导读:酷壳网的陈皓写了很多优秀的文章,这篇《如何写出无法维护的代码》相信一定能触动大家的兴奋点。 文章内容如下: 什么叫“创造力”,创造力就是——就算是要干一件烂事,都能干得那么漂亮,那么有创意的能力。
1034 0
您了解对方吗?不了解的话那就只能算是“剃头挑子一头热”了,呵呵。
     博客园就像一个大家庭,大家来自五湖四海,互相帮助,共同提高,本来是挺好的。但是如果有“与众不同”的出现的话,就很容易引起轩然大波,有关心的、有反对的、有赞成的。也有忍不住在首页跟贴的。呵呵。
647 0