找回密码
 立即注册
首页 业界区 业界 我的公司培训讲义(1):.NET开发规范教程 ...

我的公司培训讲义(1):.NET开发规范教程

兜蛇 2025-5-29 16:34:56
  1. 这是1年多以前我在公司所做讲座的讲义,现在与园友们分享,欢迎拿去使用、一起讨论。文中有若干思考题,对园友们是小菜一碟。另有设计模式讲义一篇,随后发布。<br>博文上了首页,感谢博客园团队推荐,也感谢所有园友的支持。<br>经园友提醒,我们推荐新手使用ReSharper插件,它可以自动提示不符合代码规范的地方。
复制代码
1 概述

1.1 意义

“.NET平台开发规范”包括两方面内容:代码规范、最佳实践。
(1) 规范和优美的代码风格有助于思路清晰。
(2) 规范和优美的代码有助于团队沟通交流。
(3) 规范和优美的代码有助于学**20年(后设计模式时代)现代面向对象思想发展的精华。
.NET平台是继Java平台之后又一伟大的带集大成面向对象类库的虚拟机平台。.NET平台及其主力语言C#吸取了Java平台及Java语言的全部优点和精华(包括开发规范),并逐渐发展和独创出了鲜明的、先进的特色。
众所周知,C#最初全盘照搬了Java。但时至今日,Java语言准备采用C#中的lambda语法。Java平台是个优秀的平台(类库、虚拟机),但Java语言却日益获得差评,于是JVM上的其他语言越来越多地取代了Java,如Groovy,Scala,JRuby等。
.NET平台上的语言数量比Java平台有过之而无不及,但与之截然不同的是,C#始终在.NET中保持绝对优势地位。C#也许不是.NET上最优秀的语言,但已经足够优秀来进行生产。而Java语言却称不上足够优秀,因为有语言专门用来弥补它的不足,最典型的就是Scala。而Scala解决的问题,如函数式编程、并发编程,在C#中早有解决方案。
毫不夸张地说,.NET是现代面向对象开发思想和实践的一个制高点,而C#则是编程语言发展趋势(声明性、动态性、并发性)的风向标。
即使你是一名C++开发人员,你也能从中获益。
(4) 规范是微软内部秘笈,优美是秘笈指导下的修炼。
这些规范和最佳实践多来源于微软负责CLR、BCL、C#/VB团队的成员。它们体现了.NET和C#设计人员的智慧结晶。例如,他们会告诉你哪些功能已经被哪些新功能取代而不建议使用,而新功能新方法总是以优雅的方式解决旧功能存在的问题,会给人启发,很值得回味,使用新功能收获的不仅是方便快捷,还有水平层次的提升。
1.2 后设计模式时代大事记


  • Python/Ruby等动态面向对象语言的兴起
  • Java的诞生
  • .NET的诞生
  • Boost库的发展
  • 函数式编程融入面向对象语言
  • 其他门派面向对象语言JavaScript和Objective-C的繁荣
  • 新C++标准
1.3 参考资料和延伸阅读

本教程主要综合以下资料中的观点和我公司开发实践写成:

  • 《C#编程风格》(The Elements of C# Style)
  • 《.NET设计规范:约定、惯用法与模式(第二版)》(Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition)
  • Effective C#: 50 Specific Ways to Improve Your C#, 1st and 2nd Edition
  • More Effective C#: 50 Specific Ways to Improve Your C#
1.png

2 代码规范

2.1 空白


  • 用空行分隔逻辑块(函数、条件块、循环块等)
  • 运算符空格(使用IDE自动设置)
  • 命名空间导入,在不同公司或不同库的命名空间之间空一行。
2.2 代码块


  • 切分长语句为多行语句
  • 左花括号也要单独成行,与右花括号在同一铅垂线上,与上一级花括号缩进一个制表位。
  • 始终使用语句块
复制代码
复制代码
  1. if (a == null)
复制代码
  1. {
复制代码
  1.     return;
复制代码
  1. }
复制代码
  1. if (a == null) return;
复制代码


  • 使用#region标记代码区域,便于折叠
2.3 命名


  • 使用有意义的名称,如 IsDepartmentReadyToOfferJob
  • 使用完整单词,帕斯卡(Pascal)和骆驼(Camel)写法
复制代码
复制代码
  1. NumberOfArgumentsIn
复制代码
  1. nargin
复制代码


  • 根据含义而非类型命名
复制代码
复制代码
  1. ParcelName
复制代码
  1. strParcelName
复制代码


  • 不要用大小写区分名称
  • 像普通词一样书写缩略词:XmlReader; System.Linq
  • 用复数形式书写集合名称
  • *惯性后缀(前缀):
  1. 抽象基类
复制代码
  1. -Base
复制代码
  1. 接口
复制代码
  1. I-
复制代码
  1. 异常
复制代码
  1. -Exception
复制代码
  1. 事件参数
复制代码
  1. -EventArgs
复制代码
  1. 事件委托
复制代码
  1. -EventHandler
复制代码
  1. 特性
复制代码
  1. -Attribute
复制代码
  1. 泛型类型参数
复制代码
  1. T-
复制代码


  • 给实现一种设计模式的类加上模式名称,例如:工厂模式 - xxxFactory
  • 泛型参数的命名:使用单个大写字母,如T, U等。需要时,写成TKey, TValue等
  • 枚举的命名:普通枚举用单数名词,位域枚举用复数名词。
  • 接口的命名:使用I-加名词为声明服务的接口命名,使用I-加形容词为描述能力的接口命名。(例:IEnumerable和IEnumerator)
[思考题1]
从右边找出与左边项目相关的接口。
  1. 资源回收
复制代码
  1.  
复制代码
  1. a
复制代码
  1. IFormattable
复制代码
  1. Convert.ToString()
复制代码
  1.  
复制代码
  1. b
复制代码
  1. IEquatable
复制代码
  1. 重载关系运算符
复制代码
  1.  
复制代码
  1. c
复制代码
  1. IConvertible
复制代码
  1. if (textbox1.Text == "Hello")
复制代码
  1.  
复制代码
  1. d
复制代码
  1. IClonable
复制代码
  1. Double.ToString()
复制代码
  1.  
复制代码
  1. e
复制代码
  1. IDisposible
复制代码
  1. foreach循环
复制代码
  1.  
复制代码
  1. f
复制代码
  1. IComparable
复制代码
  1. from p in q select p;
复制代码
  1.  
复制代码
  1. g
复制代码
  1. IEnumerable
复制代码
  1. 复制数组元素
复制代码
  1.  
复制代码
  1. h
复制代码
  1. IQueryable
复制代码


  • 用能体现布尔值特征的名称给布尔类型命名:IsXxx,HasXxx,CanXxx
  • 方法的命名:用动[宾]结构、帕斯卡写法
  • 变量和方法参数命名:用名词性结构、骆驼写法
  • 成组的私有字段、公共属性和构造函数形参:_item, Item, item。见3.6节代码示例
  • *惯中允许使用的标准“一次性”变量名(只限这几个):
  1. i, j, k
复制代码
  1. 循环变量(类型:System.Int32)
复制代码
  1. o
复制代码
  1. System.Object
复制代码
  1. s
复制代码
  1. System.String
复制代码
  1. e
复制代码
  1. 事件实参(基类:System.EventArgs)
复制代码
  1. ex
复制代码
  1. 异常(基类:System.Exception)
复制代码
  1. g
复制代码
  1. System.Drawing.Graphics
复制代码
  1. x, y, z
复制代码
  1. Lambda表达式的形参
复制代码


  •  命名空间的命名:公司名.产品名.技术/模块名。将相互依赖的类型放在同一命名空间下。不要污染框架命名空间(例如在System命名空间中添加类型)。
2.4 注释


  • 使用内建XML注释文档机制
  • 内部注释:尽量少用,避免行末注释
  • 不用C风格注释块/**/
  • 在右花括号、else后面加注释辅助阅读
[table][tr][td=1,1,284]
  1. 1
复制代码
[/td][td=1,1,284]
  1. 2
复制代码
[/td][/tr][tr][td=1,1,284]
  1. if (a > 0)
复制代码
  1. {
复制代码
  1. }
复制代码
  1. else // a <= 0
复制代码
返回int数组:squares.ToArray();
返回List集合:squares.ToList();
以下代码对集合foos中每个元素执行DoSomething()成员方法:
  1. {
复制代码
以下代码选出foos中大于100的元素:
  1. }
复制代码
points中点按到原点距离排序:
  1. } // end of foreach
复制代码
foos中平方最小的数:
  1. string s = "abcdeeg";
  2. s[5] = 'f';
复制代码
foos中的数是否有大于100的(是否都大于100)
  1. str.SubString(0, 3) == "abc";
  2. str.IndexOf("abc") == 0;
复制代码
3.6 返回多个值


  • 在Matlab中可以用矩阵返回多个值,这就是元组(Tuple)的概念。当函数需要返回多个值时,应当使用元组而不是使用输出参数。.NET 4.0中提供了Tuple泛型类,位于System命名空间。在3.5以下版本可以考虑自己实现。
  1. var squares = Enumerable.Range(1, 100).Select(x => x * x);
复制代码

  • 在任何时候都应避免使用ref/out传递参数,尤其对引用类型(禁止引用的引用)。尝试改进你的设计。
3.7 对象初始化
  1. foos.ForEach(x => x.DoSomthing());
复制代码
3.8 小函数


  • 将大函数分拆成小函数。这样做的好处有:

    • 合并重复代码,便于维护
    • 增加函数层级,便于调试

  • 方法参数也不宜过多,否则也应考虑拆分。
3.9 using块和finally

以下代码编译成相同IL:
  1. var q = foos.Where(x => x > 100);
复制代码
3.10 使用泛型集合


  • 不要使用非泛型的ArrayList,这会带来不必要的装箱和拆箱。使用System.Collections.Generic命名空间中的容器类型。
  • 代替数组的首选:List。如被用户代码获取应该以只读属性形式提供。如果要真的使集合不可修改,可用ReadOnlyCollection(System.Collections.ObjectModel)
  • 集合做参数禁止ref/out传递(造成引用的引用)。值传递即可达到修改集合元素的目的。
  • 在多个函数间返回、传递的集合考虑用接口类型IEnumerable和yield关键字。连续的LINQ语句考虑不急于调用ToList或ToArray。
  • 其他常用集合:Dictionary; SortedSet(.NET 4) 
3.11 充分利用BCL


  • BCL中提供了很多常用算法,并且还在不断扩充。例如,.NET 4增加了System.Numerics命名空间,目前包括BigIntegar和Complex类,而在bcl.codeplex.com上已经放出了BigRational类的候选版和源代码。
  • 尽可能只依赖BCL,减少第三方依赖。
  • 对字符串的操作都有简单的方法可以调用。用这些方法不仅能更方便省时、稳定高效,而且能使你的代码趋向于可读性强的声明式风格。
  • 尽可能只用系统定义的委托,而不是自己定义委托类型。系统定义的委托包括:各种泛型参数数目的Func, Action; 一个Predicate;各种EventHandler。以下是一个高阶函数的应用实例:
  1. var q = points.OrderBy(x => x.DistTo(new Point(0, 0)));
复制代码
3.12 其他


  • 使用虚函数和多态而不是频繁使用引用转换
  • 创建枚举0值表示未初始化、无效、未指定或默认
  • 总是在派生类构造函数的初始化列表中列出所有基构造函数
  • 总是重写ToString()方法

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册