改善C#代码的一些方法

  1. IEnumerable<T>:用于内存中的集合操作,支持延迟执行,但不支持复杂的查询优化。

    IQueryable<T>:用于与外部数据源(如数据库)交互,支持表达式树和查询优化,但依赖于特定的查询提供者。

  2. 如果局部变量的类型显而易见,则应该优先考虑使用var

  3. as运算符和is运算符只会判断对象的类型,不会执行其他操作,如果对象不是目标类型或其派生类型会失败。

    as失败会返回null,而不会抛出异常

    强制类型转换(cast)在遇到null时不会抛出异常,但需要处理两种特殊情况:对象本身为null和对象无法转换为目标类型时抛出异常。

    as运算符在这两种特殊情况下的结果都是null,因此只需if(t != null)语句来处理

  4. 内插字符串:$符号配花括号(花括号可内置三目运算、表达式、LINQ等等)

  5. nameof代替硬编码

  6. 用委托表示回调

    class Program
    {
        static void Main()
        {
            // 创建委托
            Action sayHello = () => Console.WriteLine("你好!");
            
            // 加上回调:先打招呼,然后做别的事
            CallWithCallback(sayHello);
        }
        
        static void CallWithCallback(Action callback)
        {
            Console.WriteLine("准备打招呼...");
            
            // 这里调用回调方法
            callback();  // 回调执行:你好!
            
            Console.WriteLine("打招呼完成!");
        }
    }
    

​ 设计API时的应用:可在方法的参数中设计添加委托参数(即将方法传入方法,在方法中使用传入的方法)

  • 让用户提供——无参数操作:Action
  • 让用户提供——带参数:Action< >
  • 让用户提供——判断条件:Func<T, bool>
  1. 多线程触发事件,直接判断事件是否为 null可能因事件被取消订阅而出现NullReferenceException
    应使用 ?.Invoke 方式

  2. 装箱:把值类型转换成引用类型
    解除装箱:将装有值类型的引用类型转换成值类型
    应尽量避免把值类型转换成Object类型

  3. 需要多个构造函数时尽量使用链式调用,而不是让所有的构造函数调用同一段代码

     // 主构造函数
    public Example(int a, int b)
    {
        // 这里可以添加一些初始化代码
    }
    
    // 第一个构造函数,调用主构造函数
    public Example(int a) : this(a, 0)
    {
    }
    
    // 第二个构造函数,调用主构造函数
    public Example() : this(0, 0)
    {
    }
    
  4. 频繁被调用的方法内尽量不要new对象,改用成员变量复用对象,减轻垃圾回收器(GC)的工作负担

  5. 字符串是不可变类型,创建后进行±操作时,会创建多个临时字符串对象,产生垃圾,低效。

    应该考虑使用StringBuilder (1000次±拼接耗时0.5s)

  6. 永远不要在构造函数里调用虚函数

  7. 抽象类:不能被实例化,只能被继承。
    作用:强制规范(子类必须实现父类声明的方法),可以统一处理不同类型的对象

  8. 编写泛型时应使用约束(在使用方法前使用where

  9. 优先考虑提供迭代器方法,而不要返回集合 (数据量小的时候无需过度设计)

    • 可避免被修改数据。
    • 使用 yield return 实现的迭代器方法是延迟执行的。元素只在被遍历到的时候才会被生成。
    // 提供迭代器 - 延迟执行,按需生成
    public IEnumerable<int> GetAllNumbersLazily()
    {
        for (int i = 0; i < 1000000; i++)
        {
            yield return CalculateExpensiveNumber(i); // 只在遍历到时才计算
        }
    }
    // 使用场景:调用者可能只需要前10个元素
    var numbers = GetAllNumbersLazily();
    foreach (var num in numbers.Take(10)) // 这里只会计算10次!
    {
        Console.WriteLine(num);
    }
    // 剩下的999,990个数字根本不会被计算,节省了大量资源。
    
  10. 优先考虑使用查询语句代替命令式结构

    如:

    var ans = ( from n in Enumerable.Range( 0 , 100 ) select n * n ).ToArray();
    

    Enumerable.Range()左闭右开的规则

    声明式写法举例:

    private static IEnumerable<Tuple<int, int>> QueryIndices3() {
        return from x in Enumerable.Range(0, 100)          // 数据源1
               from y in Enumerable.Range(0, 100)          // 数据源2(笛卡尔积)
               where x + y < 100                           // 过滤条件
               orderby (x*x + y*y) descending              // 排序(按到原点距离降序)
               select Tuple.Create(x, y);                  // 结果投影
    }
    

    所有主流语言的标准库都提供了高度优化的基础算法,其可靠性和性能是手写代码难以超越的。

posted @ 2026-04-01 14:19  hélium  阅读(11)  评论(0)    收藏  举报