C#代码优化

C#代码优化

参考书籍:《Effective C#》

C# 托管资源和非托管资源:https://blog.csdn.net/zlwzlwzlw/article/details/7918633

  1. 优先使用隐式类型的局部变量:即用var声明局部变量。

  2. 考虑用readonly代替const

  3. 优先用isas运算符,少用强转类型。

    • as把装箱的值类型转换成未装箱且可以为null的值类型,则会创建新的对象。
    • 判断数值类型:var i = o as int?,即判断int?可空类型是否为null。
  4. 使用内插字符串代替string.format()Debug.Log($"圆周率:{Math.PI.ToString()}")

    • 内插字符串生成的代码会调用一个params对象数组的格式化方法,所以会转成字符串,如果是数值类型,那就会有装箱操作,应该先自己转成字符串。
  5. 使用nameof()方法来获取变量名称。

  6. 用委托表示回调:

    List numbers = Enumerable.Range(1, 200).ToList();
    var oddNumbers = numbers.Find(n => n % 2 == 1);
    var test = numbers.TrueForAll(n => n < 50);
    
    numbers.RemoveAll(n => n % 2 == 0);
    numbers.ForEach(item => Console.WriteLine(item));
    
  7. 用null条件运算符调用事件处理程序,可避免被线程打断的危险操作。

    // 1.不安全
    if (Callback != null)		// 判断完后,别的线程打断,把Callback置为Null
    	Callback(this, abc);	// 这时候Callback为Null,异常
    	
    // 2.安全但冗长
    var handle = Callback;		// 浅拷贝
    if (handle != null)		
    	handle(this, abc);
    
    // 3.推荐
    Callback?.Invoke(this, abc);// 运算符左侧只计算一次
    
  8. 避免装箱拆箱。

  9. C#的GC:每次遍历对象都记一代,代数越高,检查频率越低。

    • 实现并运用IDisposeable接口,以便在不给GC增加负担的前提下把资源清理干净。
  10. 声明字段的时候最好直接初始化。

  11. 用静态构造函数初始化,捕获异常在构造函数内,如果不是,CLR会抛出TypeInitializationException以终止程序。

  12. 减少重复初始化逻辑。

    class AAA
    {
        public MyClass() : this(0, "aaa") {}
        public MyClass(int i = 0,string str = "")
        {
            ...
        }
    }
    
  13. 构建某个类型的首个实例时系统所执行的操作:

    1. 把存放静态变量的空间清零。
    2. 执行静态变量的初始化语句。
    3. 执行基类的静态构造函数。
    4. 执行(本类的)静态构造函数。
    5. 把存放实例变量的空间清零。
    6. 执行实例变量的初始化语句。
    7. 适当地执行基类的实例构造函数。
    8. 执行(本类的)实力构造函数。
  14. 频繁调用的局部引用类型的对象应该提升为成员变量。

  15. 绝对不要在构造函数中调用虚函数,因为可能基类会调用到重写后的虚函数,造成错误。

  16. 实现IDispoable.Dispose()方法时,要注意:

    1. 把非托管资源全部都释放掉。
    2. 把托管资源全部释放掉(不订阅的事件)。
    3. 设定标识说明该对象已经清理过了,如果有人要访问成员,可以抛一个异常ObjectDisposedException
    4. 阻止垃圾回收器重复请离开该对象。GC.SuppressFinalize(this)
  17. 泛型:

    • 封闭式泛型:所有类型参数都已经指明。
    • 开放式泛型:仅指出了某些参数。
    • 如果泛型类的类型是引用类型,那么无论具体指的是什么,JIT编译器都会生成同样的机器码。
    • 如果泛型类的类型是值类型,JIT编译器会根据不同的类型参数生成对应版本的机器指令。
  18. 泛型最好只定义刚好够用的约束条件。

  19. 通过IComparableIComparer定义顺序关系。

  20. 如果不需要把类型参数所表示的对象设为实力字段,那么应该优先考虑创建泛型方法,而不是泛型类。编译器可以只针对调用泛型方法的那些参数来生成代码,而不是整个类都生成。

  21. 不要在FuncAction中抛异常,这样遍历的时候,无法确定异常位置。

  22. 在方法阅读遭到违背时抛出异常。例如File.Open()在文件不存在的时候会抛异常,因为文件要求存在。

  23. 利用usingtry/finally来清理资源。编译类型支持IDisposable接口的才能用在using语句中。

你可能感兴趣的:(c#)