C#笔记:泛型、委托、lambda 表达式与部分代码规范(第四次课)

泛型(类、方法)

本质:通过尖括号<>向类中传递数据类型的参数
目的:既可以处理多种类型的参数,又保证了类型安全

委托(功能类似函数指针)与 事件(特殊的多播委托)

  1. 委托

    1. 声明:需要类似声明方法一样声明 返回值 和 参数(被委托的函数必须匹配),也可以使用系统内置的两种委托:Action,Func(通过泛型传递参数类型和返回值)
      Aciton:返回值为void,泛型传递参数类型
      Func:最后一个泛型传递返回类型,前面的泛型传递参数类型
      ps:重要的是数据类型,故使用泛型省略掉了参数名!

    2. 实例化:必要时可使用泛型对 返回类型和参数类型进行选择

    3. 使用:使用 返回值类型 和 参数类型匹配的方法为其赋值,可以使用 +、-、+=、-=等运算符为委托赋多个值,实现多播委托。(同时调用所有被委托函数)

  2. 事件(特殊的多播委托)

    • 使用的委托类型需要传入发送者参数(object sender)
    • 将委托实例化时必须使用event关键词修饰(event 不影响运行,去掉也可以)

匿名方法与 lambda 表达式

特点:可以访问匿名函数外的局部变量!(?)、简洁

  1. 匿名方法:
    格式(使用delegate作为“函数名”):delegate(argsType args...) { code body}
    (委托中已经定义返回类型,不需要再声明)

  2. lambda表达式:
    格式:(args,...) => {cods}
    委托时已定义参数类型和返回类型,不需要再次声明
    当参数只有一个时,参数列表的圆括号()可以省略,当只有一行代码时花括号可以省略(类似循环体)

异常处理

  1. 异常处理关键词

    1. try:保护区,发生异常则停止执行跳转catch异常处理区
    2. catch ([ExceptionType e]):可以有多个相连的catch,用于分别处理不同类型的异常,执行规则类似分支判断(因此更上级的异常更靠后)
    3. finally:无论是否发生异常,都执行的部分
  2. 自定义异常与异常抛出

    • 自定义异常:继承异常父类
    • 抛出异常:throw new MyException(args,...)
    • 异常抛出的传播:不断向上抛出异常,直到被 catch 捕获(一直到static Main 方法)

attribute

本质上也是一个类

  1. 自定义:通过继承 attribute 父类定义自定义attribute,可以有各种成员(本质上还是类)

  2. 使用:
    将attribute对象加在方法、类前进行修饰
    通过:class/functionType.GetCunstomAttribute(AttributeType) 可以获取在类前面的attribute对象

  3. ps:ClassType.GetMethods() 可以获取所有方法方法信息(返回 MethodInfo[]),通过MethodInfo对象可以访问该方法的 attribute

代码组织

  1. 命名空间(命名空间间可嵌套,通过‘.’访问)
    解决:避免类的重名问题
    声明:namespace xxx.xxx {}
    使用(可以使用该命名空间中定义的类了):using xxx.xxx;

  2. 嵌套类
    声明:在类内部声明的类
    使用(类似命名空间):声明所在的类.嵌套类
    访问:受声明所在的类和自身的访问控制权限控制
    场景:当该类一般仅被声明所在的类使用时

  3. ps:类本身其实也是一种命名空间?

学习作业代码规范

  1. 控制属性合法性(作业中以时间类为例):
    使用字段 + 属性控制时分秒的合法输入,非法则抛出异常。

  2. 类的实现应尽量符合实际功能(作业中以时钟为例,使用线程模拟时钟自己走时)
    有自运行功能的类可以使用线程实现(Thread)

    // 线程方法定义
    public void Run() {
            while (true) {
                DateTime now = DateTime.Now;
                CurrentTime = new ClockTime(now.Hour, now.Minute, now.Second);
                TickEvent(this);
                if (AlarmTime.Equals(CurrentTime))
                AlarmEvent(this);
                Thread.Sleep(1000);
            }
            }
    // 线程方法调用
    new Thread(clock.Run).Start();
    
  3. 事件作为一种特殊的委托通常会传入事件本身的触发者 sender(作业中以TickEvent为例)

    // 事件声明
    public event Action<AlarmClock> TickEvent;
    // 事件声明者触发事件
    TickEvent(this); // 传入自身作为参数
    // 订阅该事件
    clock.TickEvent += ShowTime;
    // 委托的函数
    private static void ShowTime(AlarmClock sender) { // 使用sender接受触发事件的对象
      /*code*/
    }