C#如何提高代码质量(二)
多线程,异步,任务和并行 1.异步和多线程应用场景区分 多线程 计算密集型工作 异步 IO密集型工作 2.线城同步中使用信号量 EventWaitHandle AutoResetEvent ManualResetEvent Semaphore Mutex 3.避免锁定不恰当的同步对象 1.需要同步的多个线程中是可见的同一个对象 2.非静态方法,静态变量不能作为同步对象 3.值类型对象不能作为同步对象 4.避免将字符串作为同步对象 5.降低同步对象的可见性 4.警惕线城的IsBackground 前台线城->线城不结束,主进程不结束 后台线城->主进程结束,线城自动结束 5.警惕线城的优先级 Thread.Priority = ThreadPriority.Highest 6.正确的关闭线城 CancellationToeknSource类的Token.isCancellationRequested方法 7.用ThreadPool或BackgroundWorker代替Thread 8.PLINQ varqueryParaller1 = from p in intList.AsParallel().AsOrdered() select p; queryParalle1.ForAll((item) =>…}); 架构篇 成员设计 1.谨慎将数组或集合作为属性 public Ilist<Object> Employees {get;private set;} 2.构造方法应初始化主要属性和字段 3.区别对待override和new 子类方法中带有new-> 独立于基类的方法 子类方法中带有override->调用该方法,而非基类的方法 4.成员应优先考虑公开基类或接口 public Ienumberable<Tresult> Empty<Tresult>(){return EmptyEnumerable<Tresult>.Instance;} 5.优先考虑将基类型或接口作为参数传递 public static Ienumberable<Tsource> Task<Tsource>(this Ienumberable<Tsource>source, int count) 6.用params减少重复参数 void Method(string str, params object[] args){} 7.静态方法和实例方法没有区别 8.使用扩展方法,向现有类型“添加“方法 public static string GetSexString(this Student student){return "";} 优点 可以扩展密封类型 可以扩展第三方程序集中的类型 扩展方法可以避免不必要的深度继承体系 约定 扩展方法必须放在静态类中,且该类不能是嵌套类 扩展方法必须是静态的 扩展方法的第一个参数必须是要扩展的类型,且必须加上this 不支持扩展属性,事件(能扩展接口,例如Linq) 类型设计 1.区分接口和抽象类的应用场合 区别 接口支持多继承,抽象类则不能 接口可以包含方法,属性,索引器,事件的签名,但不能有实现,抽象类可以 接口新增方法后,所有继承者都需要重构,抽象类不需要 场景 对象存在多个功能相近且关系紧密,使用抽象 关系不紧密,若干功能有共同的声明,使用接口 抽象适用于提供丰富功能的场合,接口倾向于提供单一的一组功能 实例 流(stream):抽象 类型(Object):接口 2.多态代替条件语句 3.使用私有化构造函数强化单例 4.静态类添加静态构造函数 特点 只被调用一次,且在第一次调用类成员之前被运行时执行 代码无法调用它,不像实例构造方法使用new就能执行 没有访问标识符 不能带任何参数 5.sealed:组织类型被其它类继承 6.类代替enum 7.避免双向耦合 A调用B,B调用A 8.将现实世界的对象抽象为类,将可复用对象圈起来就是命名空间 安全性设计 1.声明变量前考虑最大值 ushort最大后会变为0,使用checked{}来抛出此类异常 2.MD5不在安全 3.通过HASH来验证文件是否被篡改 using(MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()){ using(FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)){ return BitConvert.ToString(md5.ComputeHash(fs)).Replace(""-"", """"); } } 4.避免非对称算法加密文件 5.使用SSL确保通信中的数据安全 6.使用SecureString保存密钥等机密字符串 static Ssytem.Security.SecureSeting secureString = new SecureString(); 保存:secureString.AppendChar('w'); 取:IntPtr addr = Marshal.SecureStringToBSTR(secureString); string temp = Marshal.PtrToStringBSTR(addr); 释放:Marshal.ZeroFreeBSTR(addr); 7.不要使用自己的加密算法 DES,AES,RC4,RSA,TEA,MD5 密钥是关键 8.为程序集指定强名称 sn -k yourprofile.snk 命名规范 以<Company>.<Component>为命名空间 用名词和名词组给类型命名 用形容词组给接口命名 派生类的名词以基类的名字作为后缀 泛型类型参数以T作为前缀 以复数命名枚举类型,以单数命名枚举元素 用PascalCasing命名公开元素 考虑用类名作为属性名 用camelCasing命名私有字段和局部变量 有条件的使用前缀 代码整洁 表驱动 static void Main(string[] args){ SampleClass sample = new SampleClass(); var addMethod = typeof(SampleClass).GetMethod(ActionInTable(WeekMonday)); addMethod.Invoke(sample, null); } static string ActionInTable(Week week){ string[] methods = {""Cleaning"", ""CleanCloset"", ""Quarrel"", ""Shopping""}; return methods[(int)week]; } class SampleClass{ public void Cleaning(){Colsole.WriteLine(""打扫"");} public void CleanCloset(){Console.WriteLine(""吵架"");} } 使用时间访问器替代公开的事件成员变量 规范化开发 自动化测试(黑盒) Code UI Automation