Unity学习日志_C#基础注意事项

Unity学习日志_Unity初识_C#基础注意事项

本篇博客将整理笔者学习C#基础以来认为需要注意的一些细节和事项,内容可能并不完整且可能存在错误,欢迎各位大佬前来指正。

1. 开始

  1. C#严格区分大小写。

    1. “=”的右侧可以为表达式,但会降低代码的可读性。
    
    1. 例:

      int numA = 1,numB = 2;
      bool _isEqucal = numA == numB;
      //_isEqucal值为false
      
    2. namespace :命名空间,包含一系列的类。对类进行逻辑划分,作用:为了避免重名。

    3. using :引用xx命名空间。

    4. C#格式化输出:string.Format();如何保留空字符:char a = ‘\0’;(\0也属于转义字符的一个)。String b = “”;保留空字符串。

    5. 局部变量必须声明赋值之后才可以使用。但是成员变量存在初值,可以声明之后直接使用。

    6. C#的数据类型默认不允许使用null赋值,但在数值类型后加一个?就可以了。例如:int? = null;

    7. 声明object类型,可赋值所有类型(因为所有类型都是object的子类)。

    8. 递归能别用就别用,递归的效率相对于循环很低。

    9. 交错数组不属于多维数组。它属于数组的数组。

    10. 对于引用类型,xx[0]改的一定是堆中的数据。xx = dd;改的一定是栈中的引用。

    11. 使用数组作为形参的时候,可以选择使用 数组名.CopyTo(需要复制的数组名,开始复制的索引值)来创建新数组,这种方法依旧会对方法外原数组产生影响。

    12. 对于string和数值类型的转换永远都是tostring和Parse方法。

    13. C#命名严格遵守驼峰命名法。

    14. 面向对象的三大特点:封装,多态,继承。

    15. 和多态相关的都不能是静态。因为静态不是面向对象的。

    16. 使用父类声明中存放着子类对象的形式,调用父类虚方法,一定会调用对应子类对象的重写方法。

数据类型:

在这里插入图片描述

2. 运算符

2. 赋值运算符

  1. 赋值表达式本身也有值,所以有以下写法:

    int numA,numB;
    numA = numB = 1;
    

3. 算数运算符

  1. int型相除,结果会先被保存为int型,之后转为存放结果的变量类型。所以整形相除小数点后面的数值一定会丢失!整型和非整型相除,非整型和非整型相除没有影响。小数精度取决于非整型。
  2. 数值类型计算时特殊现象:byte+byte=int,byte+short=int,这两个数值范围小,很容易超出范围所以结果存为int型。Decimal不能和非整型相加减,因为存储的结构不同,,但可以和整型相加减。,其余情况两个数值类型做计算时,数值类型向大的靠拢。

4. 快捷运算符

  1. 快捷运算符例如“+=”,“*=”等操作实际效果如下:

    int numA = 1,numB = 2;
    numA += numB;
    //numA结果为3。等价于下面操作:
    numA = numA + numB;
    

5. 一元操作符

  1. numA++和++numA的区别:

    int numA = 1,numB;
    numB = numA++;
    /*
    效果等同于:
    numB = numA;
    numA += 1;
    */
    numB = ++numA;
    /*
    效果等同于:
    numA += 1;
    numB = numA;
    */
    

6. 三元操作符

  1. 三元操作符的语法结构:

    //数据类型 变量名 = 条件?满足条件:不满足的条件;
    string str01 = 1 > 2 ? true:false;
    

7. 逻辑运算符

  1. 计算机短路逻辑:
    1. &&:对于与运算,如果第一项已经确定为假,则不在计算第二项,结果为假。
    2. ||:对于或运算,如果第一项已经确定为真,则不再计算第二项,结果为真。
    3. 总结:当进行逻辑运算时,不论是&&运算还是||运算,尽量让计算量小的占在第一计算项。这样可以减少平均计算时间。

3. 数值转换

  1. 显式转换:由大范围到小范围的强制转换。

  2. 隐式转换:由小范围到大范围的自动转换。

    1. 隐式转换的经典例题:

      /***************/
      int numA = 1;
      numA += 3;
      Console.WriteLine(numA);
      /***************/
      byte numB = 1;
      numB += 3;
      /***************/
      /*
      问题:这两个是否一样?
      答:不一样。因为byte+int = int,但b变量是byte类型的,需要转换成byte型进行存储。
      */
      
  3. 拆装箱操作:值类型和引用类型之间的转换。

    int numA = 123;
    Object tempNum = numA;//装箱操作,Object为引用类型
    float numB = (float)tempNum;//拆箱操作
    //注意:使用“+”直接做不同类型数据的字符串连接会导致拆装箱操作。连接字符串可用下面方法实现:
    String str01 = numA.toStirng()+"456";
    
  4. 数值与字符串之间的转换:(此过程不会发生拆装箱操作但属于值类型和引用类型之间的转换)

    1. 数值==》字符串:

      数值.toString();
      

      字符串==》数值:

      想要转成的数值类型.Parse("字符串");
      

4. 内存分配

1. 内存分配:

程序运行时,CLR将申请到的内存空间逻辑划分成栈区和堆区

  1. 栈区:
    1. 空间小,读取速度快。
    2. 用于存储正在执行的方法,分配的空间叫做栈帧,栈帧中存储方法的参数以及变量等数据,方法执行完毕后,对应的栈帧会被清除。

  2. 堆区:

    1. 空间大,读取速度慢。
    2. 用于存储引用类型的数据。

2. 局部变量:

定义在方法内部的变量

  1. 特点:
    1. 没有默认值,必须自行设定初始值,否则不能使用。
    2. 方法被调用时,存在栈中,方法调用结束后从栈中清除。
  2. 局部变量中值类型和引用类型局部变量的区别:
    1. 值类型(直接存储数据):声明在栈中,数据存储在栈中。
    2. 引用类型(存储数据的引用):声明在栈中,数据存储在堆中。栈中存储该数据的内存地址。

3. 成员变量:

  1. 特点:
    1. 有初始值,可以声明后直接使用。
    2. 存在堆中。
    3. 类被实例化后存在堆中。类的实例化对象被回收时,成员变量从堆中被清除。(局部变量在方法被调用时生成)。
    4. 可以与局部变量重名。(局部变量的声明在栈中,成员变量在堆中,所以可以相互之间重名)。在一起使用的时候用this指代。
  2. 成员变量中值类型和引用类型局部变量的区别:
    1. 值类型(直接存储数据):声明在堆中,数据存储在堆中。
    2. 引用类型(存储数据的引用):声明在堆中,数据存储在堆中。

5. 循环语句

  1. for

    for循环的应用:预定次数的循环,遍历循环。累加累乘等操作。

  2. while

    while短路逻辑:

while(ture){
	if(结束条件){
		break;
	}
	//循环体
}

​ 3. foreach:非常适合遍历数组

​ 1. 语法:foreach(var item in array){

​ 方法体

​ };

​ 2. 其中item变量代表数组中的项,无法赋值,array为需要遍历操作的数组。

​ 3. 优点:对于遍历操作十分方便。

​ 4. 缺点:仅限于遍历方便。性能不如for循环。不能修改元素(赋值)。

6. 分支语句

  1. if else
  2. switch
    1. switch选择语句中,case后跟的是括号里变量或表达式的具体值。且括号里的变量不能为单纯的非整型变量(float之类)。
      1. 原因是switch的判断条件只能是等于,对于数据类型的精度要求比较高。字符型、布尔型、枚举型都可以转换成整型进行判断,是因为整形在相等不相等上有很大的确定性,而float和double表示的小数,毕竟精度都是有限的,超过限度以后的等于和不等于计算机就不好判定,故不能用。

在这里插入图片描述

7. 方法

  1. 有返回值类型的方法的返回值只要是可兼容(可以隐式转换的)的就行。比如:float返回值类型可以返回一个int变量。
  2. return语句的作用:返回数据,退出方法。对于返回值类型为void的方法内部可以写return;表示退出方法。
  3. 方法体应当写的小,这样代码的重用率会更高。
  4. 书写大型方法时的处理原则:分而治之。

1. 方法重载

  1. 方法重载:在不同条件下解决同一类相似问题可以使用相同的方法名(参数的类型,数量不同),不同方法之间根据参数来区分。当然方法体通常来说是有区别的。这样做可以让调用者只需要记住一个方法就可以了。

2. 递归

(1) 核心思想:将问题转移给范围缩小的子问题。

(2) 优势:可以将复杂的问题简单化;可以使用代码体现数学公式的思想。

(3) 缺点:性能较差。原因是每次递归的时候都需要在内存上开辟一段新的空间,每次return返回时都需要释放内存上开辟的空间。

(4) 适用性:当解决问题时发现了相同的规模更小的子问题时,可以用递归解决。

(5) 在写递归的时候一定要注意结束递归的条件不能丢。

8. 数组

  1. 数组:在内存上开辟的连续的一块空间,用于存储若干个相同类型的数据。

  2. 数组通过索引来访问数组内的数据,从0到数组.length-1。

  3. 可以使用foreach来遍历数组。

  4. 一维数组和交错数组动态获得数组长度:array.Length();

  5. 二维或多维数组动态获得数组长度:

    1. array.GetLength(0)获取行数。

    2. array.GetLength(1)获取列数。

    。。。。。。

    初始化交错数组时,其元素的new运算符不可省略。

10. 参数

  1. 参数数组:
    1. 关键字:params
    2. 适用性:当所需传入的参数类型固定但数量不固定时可以使用。
    3. 使用参数数组和不使用参数数组的区别(Add方法为参数列表为数组的累加方法):
      1. 使用params:Add(1,2,3,4,5,8,45);
      2. 不使用params:Add(new int[]{1,2,3,4,5,8,45});
    4. 优势:使用params对于方法内部没有影响,对于方法外部可以传入数组,可以传入一组类型相同的数据,也可以传入一组类型相同的变量。甚至可以不传递参数。方便调用者调用方法。
  2. 输出参数:
    1. 关键字:out
    2. 传递实参变量的引用(地址)这一点和引用参数相同。
    3. 作用:返回结果。传递的实参变量本身作为了存储结果的变量。
    4. 特点:使用前实参变量可以不赋值。
  3. 值参数:
    1. 无关键字默认就是值参数。
    2. 值参数的传递就是赋值的过程,即变量中存的是什么就传递什么。
  4. 引用参数:
    1. 关键字:ref
    2. 传递变量的地址。
    3. 对于ref参数,传进来的为变量的地址,当修改时修改的是变量所直接存放的数据。
    4. 值参数和引用参数的区别(以new新数组为例,上图为值参数,下图为引用参数):

在这里插入图片描述
在这里插入图片描述

11. 垃圾回收器GC

1. 产生垃圾的原因:当方法执行完后,对应的栈帧会被清除,此时值类型数据会随之一起被清除,但引用类型只是清除了一个指针,对应的堆中的数据并没有清除,此时就产生了垃圾。
2. 垃圾回收时会占用大量的计算机资源,所以在实际项目开发时要尽量选择时段进行垃圾回收。
3. 一般情况下,GC会在内存空间不够的时候进行自动调用。
4. GC工作原理:GC线程会跟踪栈中的引用,如果GC无法跟踪到某一个堆中的内存,则认为这块内存是垃圾,标记为可回收(不会立即回收)。

12. string类型

1. C#中的String和string的区别:

  1. string是c#中的类,String是.net Framework的类(在c# IDE中不会显示蓝色) 。
  2. c# string映射为.net Framework的String 。
  3. 如果用string,编译器会把它编译成String,所以如果直接用String就可以让编译器少做一点点工作 。
  4. 如果使用c#,建议使用string,比较符合规范 。
  5. String只有在前面有using System;的时候并且当前命名空间中没有名为String的类型(class、struct、delegate、enum)的时候才代表System.String 。
  6. string是关键字,String不是,也就是说string不能作为类、结构、枚举、字段、变量、方法、属性的名称,而String可以 。

2. string的特性:

1. 不可变性:
  	1. string类型作为C#的引用类型,其内部存储的数据是不可改变的。原因是无法得知接下来要存储的字符串大小,如果强行存入则会导致内存溢出。Object类型也存在这个特性。
2. 字符串池:
	1. 当一个新的字符串常量被创建时,都会先去字符串池中查看是否存在相同的文本。如果存在,则直接返回该对象的引用,否则创建新的字符串常量存储在字符串池中。目的:提高内存利用率。

13. 枚举

1. 枚举:用于使数值类型01234产生逻辑意义。相当于给01234这类数据添加了个标签。枚举类型与类同级但属于值类型,可以写在类内部和外部。
2. 当想要一次性选择多个枚举常量时:
  	1. 枚举值的要求:任意多个枚举值做|(按位或,也就是讲一个数转换成二进制后各个位对应做或操作)操作结果不会和其他枚举值冲突。(值以2的n次方来设置,这样可以保证做按位或操作时结果不会冲突)。
  	2. 定义枚举时用[flags]修饰,程序员内定的规则。
  	3. 当想要输入多个枚举值时,使用枚举值做|操作的方式传入。
  	4. 方法内部使用&(按位与)操作,&的结果不为0说明包含。
3. 枚举类型的数值转换:
	1. int ==》enum,显式转换直接转。
	2. enum ==》int,显式转换直接转。
	3. enum ==》string,tostring()方法。
	4. string ==》enum, enum.Parse方法。

14. 类和对象

  1. 通常每个类都在一个独立的cs文件中。

  2. 类中的变量默认为private,但是为了规范要自己手动敲出来。

  3. this关键字:this中存放当前调用方法的对象引用。

  4. 对象是类的实例,调用构造函数才会产生类的实例。

    Wife wife01 = new Wife();//调用构造函数之后,此时wife01成为Wife类的实例
    wife01.Cooking();//此时Cooking方法中的this指代的就是wife01
    
    1. 创建的类在堆中需要内存空间的大小取决于类中声明的字段。
  5. 自动属性不能限制存入字段中的数据,普通的公开属性可以限制。

类的进阶应用:

  1. 类(结构)属性进阶应用:定义以自身类型为返回值的方法或属性。此类用法应定义在构造函数之后。原因:返回对象需要new使用构造函数,且对象内包含的数据是类(结构)的字段,所以需要放在他们后面。

1. 构造函数

1. 构造函数:构造类的对象的函数,提供创建对象的方式,常常用于初始化类的数据成员。(类中没有构造函数时,会自动提供无参构造函数)构造函数没有返回值。构造函数只在new的时候调用一次。所以适合初始化。
2. 使用构造函数初始化的时候,建议使用属性赋值,因为通常情况下属性中存在数值限制。
3. 构造函数不能被外部手动调用,但构造函数可以调用构造函数。
4. 在构造函数后面加:this(参数列表)就可以调用对应的构造函数。

2. 访问修饰符

1. public:类的内部和外部都可以访问。
2. internal:同一程序集(namespace)的可以访问,程序集外的不能访问。
3. protected internal:类的内部,继承该类的子类或者另一程序集继承该类的类可以访问。
4. protected:类的内部和继承该类的子类可以访问。
5. private:类的内部可以访问。

15. 继承

  1. 继承的特点:
    2. 子类可以继承父类成员,但只能使用父类的非私有成员。(私有成员会被继承,但受限于修饰符限制子类无法使用)
    3. 父类不可以使用子类成员。
    4. 继承时基类的构造函数不被继承。
    5. 父类引用可以指向子类对象。但只能使用父类成员,或者子类的重写方法。
  2. 适用性:不同类之间存在相同的代码,则将相同的代码提取出来作为这几个类的父类。
  3. 其他叫法:父类也叫基类,子类也叫派生类。
  4. 继承的特性:
    1. 单根性:一个派生类只能有一个基类(可以有多个接口)
    2. 传递性:可以将继承想成树结构,子节点的类可以继承向上回溯所有父节点类的非私有字段。
  5. base关键字:由于基类在子类被创建时会在子类对象中创建基类对象,base指的就是这个基类对象(base指向直接基类),是这个子类对象独有的。
  6. 一个类或者结构体只能继承一个基类,但可以继承多个接口。

关于构造函数

  1. 关于构造函数的继承:首先需要明确的是,子类并没有继承父类的构造函数。因为如果父类中存在私有字段,子类的实例就无法对父类的私有字段赋值。
  2. 问题解决:C#中,当创建子类对象的时候会调用子类的构造函数,这时候C#会从扩充类以此向上寻找基类,当找到最初的基类后,依次向下执行无参构造函数,最后执行子类的构造函数。原因:子类想要调用父类的成员就需要有父类对象。所以要调用父类的构造函数。
  3. 例子:有A,B,C,D四个类,且A->B->C->D(D为基类)则创建A对象的时候构造函数的执行顺序为:D,C,B,A。
  4. 如果new的是子类的全参构造函数需要通过:base(参数列表)调用父类的全参构造函数。

16. 静态(包含静态和实例的一些比较)

1. 静态成员变量:

  1. 静态成员变量:在类中,带有static修饰符的字段为静态成员变量。类中分为实例成员变量和静态成员变量。
  2. 静态成员变量属于类,类在被加载时初始化(在C#中类名一旦被提及,对应的类就会被加载装入内存),且只有一份存储在内存中的“静态区”。
  3. 实例成员变量属于对象,在每一个对象被创建时初始化(对象创建时需要开辟多大的空间取决于实例成员变量),且每个对象一份。
  4. 特点:存在优先于对象,被所有对象共享,常驻内存。

2. 静态构造函数:

  1. 静态构造函数&(实例构造函数):
    1. 初始化类的静态数据成员。(初始化类的实例数据成员)
    2. 仅在类被加载时调用一次。(仅在创建对象时调用一次)
    3. 不能使用访问修饰符。(可以使用访问修饰符,一般为public)

3. 静态方法不能访问实例成员:

  1. 静态方法只能访问静态成员:当对象调用实例化方法时会传递对象自身的引用,这样方法才能知道是谁调用了自己。并可以使用实例成员。而静态方法是类的方法,调用时不需要引用,故不能访问实例成员。实例方法在被调用时才会被装入内存。

4. 优点:

  1. 单独空间存储
  2. 可被本类的所有对象共享
  3. 可直接被类名调用

5. 缺点:

  1. 静态方法只能访问静态成员
  2. 共享时会出现并发。

17. 密封类

1. 关键字:sealed
2. 用途:
  	1. 防止继承的滥用而导致项目结构过于复杂。
  	2. 防止重写方法被再次改写。
3. 注意:
	1. 密封类中不能包含虚方法(Virtual)和抽象方法(abstract),因为在密封的类没有为派生类提供实现其虚方法和抽象方法的机会。如果想要密封这个类,这个类必须是“完整的”。
	2. 密封方法必须是重写方法。
	3. 静态不能密封。

18. 结构体

1. 语法:与类基本相同。

  1. 使用关键词定义(结构:struct,类:class)。
  2. 语法结构包含字段,属性,构造函数,方法。
  3. 非带有static,const修饰的字段不可直接初始化。(由于类相对于构造体更为常用,所以在类中编译器会根据习惯来自动为开发者做一些事情)
  4. 构造函数中需要初始化所有字段或者不做初始化。

2. 结构体相对于类的区别:

  1. 结构是值类型,直接存储数据;类是引用类型,间接存储数据。
  2. 结构的无参构造函数不能写,编译器自带。
  3. 结构中如果要使用自动属性,需要构造函数调用无参构造函数来辅助实现。
  4. 结构不能继承,但可以实现接口。

3. 适用性:

  1. 表示坐标,颜色(RGBA)等轻量级对象,原因是方法调用结构的时候,结构对象的值存储在栈(空间小,不适合存储大量变量)中。
  2. 表示坐标这种变换频繁的变量。因为方法中的结构对象存储在栈中,频繁改变不会产生垃圾。

19. 抽象类

1. 关键字:abstract
2. 抽象类只能做其他类的基类。不能实例化。
3. 派生类需要实现所有的抽象方法,普通方法不用管。
4. 当基类中有方法不确定方法体时就可以使用抽象类。

20. 接口

接口特点:

  1. 接口完全抽象,内部不可以有实现的方法。
  2. 一个类可以继承一个基类和多个接口。
  3. 接口适合用来做小而简炼的功能。
  4. 接口命名:IXXXable。
  5. 接口中只能包含方法,属性,索引器和事件声明,不能包含构造函数,也不能包含字段。
  6. 接口中都隐式声明为public(类里默认private),不能再用public声明。
  7. 接口可以用类或者结构实现。
  8. 接口不能实例化。
  9. 接口只能继承接口,类可以继承接口也可以继承类。
  10. 接口可以多继承,可以用一个接口将多个需要继承接口集合在一起,再由类去继承。
  11. 继承接口的方法必须全部实现,而继承抽象类则需要实现所有抽象方法。

显示实现接口:解决方法重名问题。

  1. 实现接口方法时命名采用:接口名.方法名。

接口的作用:

  1. 代码通过接口定义来表明自己对外开放的能力,具体的实现则交给实现这个接口的类。只要实现了这个接口的类,都一定存在对应的方法,那么我拿到这个类的实例对象的时候,就一定可以调用这个对象所实现的方法。

21. 多态

多态:C#中关于多态的定义是同一操作(相同的方法)可作用于不同类的实例,且有不同的执行结果。

1. 实现多态1:虚拟方法和重写方法。

  1. 在基类中用virtual标记的方法称之为虚拟方法,可以在扩充类中使用override重写此方法。

    1. 重写的方法的返回值类型,参数个数,类型,方法名称都需要和虚拟方法一致。
    2. 虚拟方法不能是static类型,因为多态是面向对象的需要实例化。
    3. 虚拟方法不可以是private类型。因为子类不能访问父类的私有对象。
  2. 补充:new隐藏方法:

    1. 当基类无法被修改但又不是虚方法,需要使用new来隐藏基类中的同名方法。

2. 实现多态2:实现抽象类。

3. 实现多态3:实现接口。

22. 泛型

1. C#泛型集合类:集合类型<数据类型>,比如List<User>,c#泛型集合类本质是对特定类型数组的封装,直接操作数组比较麻烦,所以就把一些特定功能和数组一起封装在了一个集合类中。集合类型包括:List<Type>列表,SoredList<TKey,TValue>排序列表,Dictionary<TKey,TValue>字典,Queue<Type>队列,Stack<Type>栈。
2. 强烈推荐使用泛型集合类而不使用非泛型集合类,虽然两者都是对于数组的封装,但非泛型集合类没有指定数据类型,这导致了频繁的拆装箱操作和不安全数据类型问题,泛型集合通过指定数据类型很好的解决了这两个问题。

where

  1. where用于限定泛型的范围。

  2. 可以限定特定类型where T :int

  3. 可以限定是引用类型还是值类型:

    1. where T :class//限定引用类型
    2. where T :struct//限定值类型
  4. 可以限定构造函数的类型:

    1. where T :new()//类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
  5. 可以是限定为一个接口:

    1. where T :Iinterface//其中T必须是一个实现了接口的类型
  6. 可用于泛型类,泛型方法,泛型委托

23. 委托&事件

委托(引用类型):

  1. 特点:所有的方法都可以通过委托来调用。委托相当于是C++中的函数指针,存放方法的引用。

  2. 可以将委托理解成方法的多态,同一个委托可以调用不同的返回值类型,参数相同的方法。

  3. 语法:

    1. [访问修饰符] delegate 返回类型 委托名(参数列表);
  4. 通过委托调用方法:

    1. 直接使用方法名,前提是该方法与传入的委托类型有相同的返回值类型和参数列表。
    2. 实例化委托(将方法引用存放到委托中),调用委托。
    3. 注意这时候传进来的对象是一个方法。
  5. 通过委托可以调用静态方法,也可以调用实例方法。

事件(本质还是委托):

事件的本质是委托,其是利用委托来实现的,所以和对应委托有相同的返回值类型和参数列表。同时注册事件的方法也需要有相同的返回值类型和参数列表。注:这导致事件和其委托返回值类型为void。

  1. 事件声明:

    1. 先声明一个委托:
      1. public delegate void MyEventHandle();
    2. 利用委托声明事件:
      1. public event MyEventHandle MyEvent;
  2. 事件注册:

    1. 使用 “+=” 注册,使用 “-=” 取消注册。注册的方法可以为委托。单委托在注册的时候需要实例化。注册的过程其实就是将引用传给事件的过程。被注册的方法叫做事件处理方法。
  3. 事件被触发的过程:

    1. 事件触发–》调用OnXXX方法–》调用事件–》根据注册事件调用对应的事件处理方法。
    2. 其中OnXXX方法需要和被监测对象(可以是属性(通常用于监测字段变化),可以是方法)放在一起。
    3. 一旦调用了OnXXX方法,后面就会连锁调用。
  4. 具有标准签名的事件:

    1. 在绝大多数情况下使用的都是具有标准签名的事件。
      1. public delegate void EventHandler(object sender, EventArgs e);
      2. public delegate void EventHandler (object sender, TEventArgs e);
    2. 其中EventHandler用于不包含事件数据的事件,EventHandler用于包含事件信息的事件。如果没有事件数据,可将第二个参数设置为EventArgs.Empty,否则第二个参数类型需要从EventArgs类继承。

24. Lamda表达式

  1. 语法:

    1. (参数列表)=>表达式/{语句块};
    2. Lambda表达式或者语句块是没有return。
  2. Func委托和Action委托使用Lambda表达式:

    1. Func委托和Action委托都属于官方提供的泛型委托,一般直接拿来用就可以,不需要自己定义新的委托。
    2. Func委托是带返回参数的委托,Action委托则是void委托。
//正常委托实例化应该是这样的:
Func<int,int> MyFunc1 = new Func<int,int>(Class.Function);
//使用Lambda实例化:
Func<int,int> MyFunc2 = n => n*3;
//使用匿名委托:
Func<int,int> MyFunc3 = delegate(){return Class.Function};
//所以lambda表达式YES!

ntArgs e);
2. 其中EventHandler用于不包含事件数据的事件,EventHandler用于包含事件信息的事件。如果没有事件数据,可将第二个参数设置为EventArgs.Empty,否则第二个参数类型需要从EventArgs类继承。

24. Lamda表达式

  1. 语法:

    1. (参数列表)=>表达式/{语句块};
  2. Func委托和Action委托使用Lambda表达式:

    1. Func委托和Action委托都属于官方提供的泛型委托,一般直接拿来用就可以,不需要自己定义新的委托。
    2. Func委托是带返回参数的委托,Action委托则是void委托。
//正常委托实例化应该是这样的:
Func<int,int> MyFunc1 = new Func<int,int>(Class.Function);
//使用Lambda实例化:
Func<int,int> MyFunc2 = n => n*3;
//使用匿名委托:
Func<int,int> MyFunc3 = delegate(){return Class.Function};
//所以lambda表达式YES!
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值