改善C#程序的建议

nd | | 访问(349)

  总结一下,C#开发时,需要注意的细节知识,阅读《编写高质量代码:改善C#程序的157个建议》

  一、正确操作字符串

  字符串使用原则,尽量少的使用装箱,避免分配额外的内存空间。

  string s1 = "你好"+10.ToString();// 将值类型10 ToString 后 避免了装箱(值类型的ToString方法是直接更改内存,效率高)

  字符串对象一旦赋值不可更改,执行运算(如“=”赋值、“+”拼接等)都会创建一个新的字符串对象即新的内存空间

  1、string s1 = "abc"; s1 = "123"+s1+"456"; //这一行代码创建了3个对象

  2、string re1 = "123"+"abc"+"456"; 等价于 string re1 = "123abc456";

  3、const string a = "t"; string re1 = "abc"+a; 等价于 string re1 = "abct";

  4、

  string a1 = "t"; a += "e"; a += "s"; a += "t";

  string a2 = "t"; string b = "e"; string c = "s"; string d = "t"; string result = a+b+c+d;

  a1 和 a2 输出结构一样,但两者效率都不高,a1 执行了3次string.Contact(字符串合并) a2只运行了1次。

  StringBuilder 只创建一个对象,默认分配字符长度为16,超过则16的倍数递增(重新分配内存)

  string.Format 其实是封装了的StringBuilder,不过对于字符超长的,不适宜用string.Format

  总结:如果简单的字符串拼接可以使用string,string.Format在处理小量字符串时效率高,如果字符串数量多(如:循环拼接字符串),用StringBuilder会更搞笑。

  二、使用int?来确保值类型也可以为null

  int? i = null; 是 Nullable的简写

  1、基元类型提供了其对应的可空类型的隐式转换

  int? i = null; int j = 0; i=j;

  2、可空类型不可隐式转换为对应的基元类型

  int? i = 123; int j = i?? 0;//??表示 如果i的HasValue为true,将赋值给j否则给j赋值为0

  基元类型(primitive type)

  编译器直接支持的类型。

  sbyte / byte / short / ushort / int / uint / long / ulong / char / float / double / bool / decimal / object / string

  值类型(value type)

  值类型实例分配在堆栈(stack)上,值类型变量本身即包含实例所有字段,值类型不受垃圾回收器控制,在离开作用域后自动释放所占内存。所有值类型都继承自ValueType。值类型缺省状态下(未装箱)按值复制方式传递。

  sbyte / byte / short / ushort / int / uint / long / ulong / char / float / double / bool / decimal / 枚举(enum) / 结构(struct)   引用类型(reference type)

  引用类型都全部或间接继承自Object,引用对象内存必须在托管堆(heap)中分配,引用类型变量包含对象在托管堆中的内存地址。每个引用类型对象实例都包含一些额外附加成员,且需要垃圾回收器回收才能释放内存。注意,引用本身在堆栈中分配。引用类型对象传递时只是复制引用(内存地址)。

  引用对象(Object) / 数组(String) / 数组(Array) / 装箱后的值类型

  区别对待==和Equals

  多数情况下使用foreach进行循环遍历

  foreach 优势:(1)自动置入try-finally (2)若类型实现IDispose接口,循环结束自动调用Dispose方法

  foreach 劣势:(1)不支持循环时对集合进行增删操作,集合增删操作会使集合版本的版本号加1,MoveNext方法检测版本号变更就会抛出异常

  使用for可以增删集合

  using 是 try-finally 的语法糖 两者等效

  使用泛型集合代替非泛型集合 List效率高于 ArrayList , ArrayList执行Add方法会完成一次装箱 循环遍历又将完成一次拆箱,ArrayList 的 添加和遍历是非类型安全的,缺少编译时的类型检查,会在运行时带来隐藏的Bug。

  集合

  分为 线性和非线性。

  线性集合是指元素具有唯一的前驱和后驱的数据结构类型,非线性集合是指具有多个前驱和后驱的数据结构类型。

  线性集合

  分为 直接存储和顺序存储

  直接存储:是指该类型的集合数据元素可以直接通过下标(即index)来访问, 分三类 (1)Array(数组,List)、string、struct。直接存储的优点是,向数据结构中添加元素是很高效的,直接放在数据末尾的第一个空位上,缺点是向集合插入元素低效。

  顺序存储:即线性表,可以动态扩大和缩小,它在一片连续的区域中存储数据元素。线性表不能按照索引进行查找,它是通过对地址的引用来搜索元素的,为查找某个元素,它必须遍历所有元素,直到找到对应的元素为止,所以,线性表的优点是插入和删除数据效率高,缺点是查找效率相对低一些。

  顺序存储

  分为 队列(Query)、栈(Stack)及索引群集

  索引群集

  分为 散列、字典(Dictionary)、链表(LinkedList)

  非线性集合

  分为 层次群集(数)和 组群集

  组群集

  分为 集(HashSet)和 图

  理解延迟求值和主动求值之间的区别

  Listlist = (Linq对象).ToList(); 之后会执行查询操作,将内容存入内存

  不要过早的执行 ToList 做到延迟求值 减小服务器压力

  使用Linq取代集合中的比较器和迭代器

  在Linq查询中避免不必要的迭代

  充分运用First和Take等方法,提高查询效率,避免通篇查询所有数据才返回数据