目录
14.4 虚方法(virtual)和覆写(重写)方法(overrider)
14.5 其他类型的virtual成员和override方法
参考菜鸟教程:https://www.runoob.com/csharp/csharp-data-types.html
一、c#基本语法
注意点:
C#是大小写敏感
所有的语句和表达式必须以(;)结尾
于java不同的是,文件名可以不同于类的名称
using :引用命名空间
namespace : 声明命名空间
class : 声明类
1. 注释
单行注释: //
多行注释(块注释):/* */ 、
文档注释:///
2.关键字
3. 插值字符串
作用 :拼接字符串
格式化字符串
4. 数据的类型
在 C# 中,变量分为以下几种类型:
- 值类型(Value types)
- 引用类型(Reference types)
- 指针类型(Pointer types)
值类型(Value types)
引用类型(Reference types)
对象(Object)类型
对象(Object)类型 是 C# 通用类型系统(Common Type System - CTS)中所有数据类型的终极基类。Object 是 System.Object 类的别名。所以对象(Object)类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。
当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。
动态(Dynamic)类型
您可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。
声明动态类型的语法:
字符串(String)类型
字符串(String)类型 允许您给变量分配任何字符串值。字符串(String)类型是 System.String 类的别名。它是从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号和 @引号。
指针类型(Pointer types)
5. 变量
变量的的类型:
注意点:
浮点数:
float x = 1.1F;不加后缀F,系统会默认double类型
十进制类型:
decimal z = 1.1M 不是基础类型,不能和float,double相互转换
拓展:
本地变量 -- 写在方法里
字段-- 是类成员,用来保存类型或者类型实列相关的数据。
方法参数-- 他是一个临时变量
数组元素-- 可以为本地变量或者类型成员
本地变量和参数使用一定要初始化
6. 实例化和初始化
实例化: 分配内存空间
初始化:往内存空间里面填数据
7. 栈和堆
数据分类:
二、类--基础
1. 类的介绍
类是一种灵活的数据节后,它包含了数据成员和函数成员,成员没有数量的限制,可多可少,也可以没有
2. 类成员--字段和方法
3. 类的实例化
4. 访问修饰符
private私有 -- 成员默认修饰符-- 内部访问 (默认情况下)
publicl公有 -- 外部访问
protected受保护
internal 内部的
protected internal 受保护内部的
例如
三、方法
一个方法是把一些相关的语句组织在一起,用来执行一个任务的语句块。每一个 C# 程序至少有一个带有 Main 方法的类。
1. 定义方法
当定义一个方法时,从根本上说是在声明它的结构的元素。
下面是方法的各个元素:
- Access Specifier:访问修饰符,这个决定了变量或方法对于另一个类的可见性。
- Return type:返回类型,一个方法可以返回一个值。返回类型是方法返回的值的数据类型。如果方法不返回任何值,则返回类型为 void。
- Method name:方法名称,是一个唯一的标识符,且是大小写敏感的。它不能与类中声明的其他标识符相同。
- Parameter list:参数列表,使用圆括号括起来,该参数是用来传递和接收方法的数据。参数列表是指方法的参数类型、顺序和数量。参数是可选的,也就是说,一个方法可能不包含参数。
- Method body:方法主体,包含了完成任务所需的指令集。
2. 本地变量
3. var 关键字和类型推断
从 C# 3.0 开始,在方法范围内声明的变量可以具有隐式“类型”var。隐式类型本地变量为强类型,就像用户已经自行声明该类型,但编译器决定类型一样。i 的以下两个声明在功能上是等效的:
var特性:
var 只能用于本地变量 不能用于字段 也不能用于参数
只能用在包含初始化的声明中
一但推断出来后,他值就固定不能修改
4. 本地常量const
常量是使用 const 关键字来定义的 。
声明是必须赋值
申明后值不允许改变
5. 方法调用的执行顺序
6. 实参和形参
例如:
7. 参数传递
7.1 值传递
注意:
1.在栈中为内存分配空间
2.将实参的值复制给形参
3.参数值传递和值类型是两个不同的概念,值类型指本身包含值,从存储位置来说,参数吃传递是八实参的值复制给形参,是从参数传输角度来说的
7.2 引用传递--ref关键字
注意:
1.在声明和调用都要用ref关键字
2.实参必须是变量
3.不会在栈上分配内存
4.实际情况是形参的变量名作为实参的变量的别名,指向相同的内存位置
和之前比修改的地方:
8. 输出参数-- out关键字
1. 用处 -- 吧方法体内的数据输出到调用代码
2. 在声明和调用中都用out关键字修饰
3. 参数必须是变量 -- 因为方法需要内存的位置保存返回值
4. 在方法内部输出参数在读取之前必须赋值, 在调用之前可以不初始化
5. 方法返回前必须赋值
例:
逻辑图:
9. 参数数组
什么是数组?
1. 数组是一组相同类型的数据集合。
2. 数组使用一个数组索引进行访问,位置从第0个位置开始
3. 数组是引用类型,他的数据向都保存在堆中
声明数组:
初始化数组:
给数组赋值:
参数数组:
1. 在形参数据类型前用params修饰
2. 实参是一个和形参类型相同的数组
3. 直接在实参中定写出传递的参数列表,每个参数之间逗号分开
4. 通过一个一维数组传递
例:
参数方法总结:
10.方法重载
多个方法的名称相同,参数不相同。
重载方法的目的:让我们调用方法变得简单
形成重载的条件:
1. 方法名称相同
2. 或者参数的数据类型--不同
3. 或者参数的个数--不同
4.或者单数的顺序--不同(前提是参数个数或者类型不同)
5. 或者参数修饰符(部分情况比如ref修饰符)--不同
例:
11.命名参数
1. 在调用方法时实参顺序可以和形参不一样,可以通过指定参数名称来传递参数。
2. 注意位置参数和命名参数是可以同时使用的,不过需要先列出位置参数。
参数位置: 形参和实参的位置是一一对应的。
注意:位置参数一定要放在前面,命名参数放在后面
12.可选参数
可选参数就是在调用方法的时候可以包含这个参数,也可以不包含(可有可无)
注意:不是所有参数类型都可以作为可选参数
13.栈帧
栈帧:在调用方法的时候,操作系统为方法分配了了一块内存,用来保存和方法相关的数据。这块内存叫做方法的栈帧。
主要作用:用来控制和保存一个过程的所有信息。
保存的内容有:返回地址,参数,各种方法调用相关的的其他管理数据项(动态连接,操作数栈,方法内临时变量)。
例:
14.递归
常用场景: 多级菜单, 算法中的阶乘,排序
递归:方法自己调用自己
注意点:一定要设置弹出条件
四、类--进阶
1.类成员和成员修饰符
类成员:
成员的修饰符:
2.实列-实列成员
实列(或者叫做对象):在内存中根据类创建了一块内存空间,这块内存空间就是实列,取的名字叫做变量或者字段。
实列成员:类的每一个实例拥有自己的各个类成员的副本,这些成员为实列成员。
实列字段:改变一个实列字段的值不会影响任何其他实列中成员的值
3.静态字段
静态字段属于类 不属于类的实列
除了实列字段,类还可以拥有静态字段
【1】静态字段被在所有实列共享,所有时刻额都访问同一内存位置。
【2】使用static修饰符将字段声明为静态的。
【3】作用:1.记录已事实列化的对象的个数。2.--存储必须在所有实例化之间共享的值
4. 静态成员访问和生命周期
【1】静态成员不能直接访问实列成员,可以直接访问其他静态成员
【2】生存期:程序启动时 =》 程序结束
5. 成员常量和静态成员变量
【1】成员变量前佳const==成员常量
【2】类似于与静态变量,对于每个实列都是可见的,但没有自己的存储位置,而是在编译的时候被替换
区别:
【1】静态变量用于多个实列访问同样的数据。
【2】常量用于在程序中永远不会变化的数值或者其他类型的变量 例如:圆周率PI
相同点:
都是不用实例化可以直接访问
例如:
6. 属性
【1】属性是对成员字段的包装,是用来控制我们成员字段读取和写入,使用和字段类似
【2】属性是函数成员,是执行代码的成员,不为数据存储分配内存
【3】属性是由两个方法组成,我们也称之为访问器,set方法设置数据,get方法读取数据
6.1 属性添加业务逻辑
set 和 get 方法里面可以添加一些逻辑
7. 构造方法
【1】构造方法也叫 构造器 或者构造函数
【2】构造方法名称和类名相同,不能有返回值和返回类型
【3】构造方法是一种特殊的方法,它在实例化类的时候调用
【4】如果要从类的外部实例化类,就要将构造方法申明为public
【5】编译器默认会生成一个无参数,方法体为空的构造方法
【6】如果显示定义了一个构造方法,那么编译器就不会生成默认的构造方法了
8. 静态构造方法
【1】重点:类只能有一个静态构造方法,而且不能带参数,不能有访问修饰符。
【2】不能用手动去调用,系统会自动调用。
【3】系统会在类的任何实例创建之前 和 类的任何静态成员被引用引用之前
【4】作用:初始化静态成员
【5】静态构造方法写了 才有,不写就没有
9. 对象初始化器
作用:减少初始化工作量
10. readonly 修饰符
【1】 const 编译时常量,只读,没有分配内存空间,定义时就必须初始化。
【2】readonly 运行时常量,可以是实列也可以是静态的,有分配内存空间。可以在构造方法内初始化。
例:
11. this 关键字
【1】指代类的当前实例--用于区分类的成员和本地变量或者参数
【2】将对象作为参数传递给方法
【3】声明索引器
【4】拓展方法的第一个参数的修饰符
例:
【1】指代类的当前实例--用于区分类的成员和本地变量或者参数
例:
【2】将对象作为参数传递给方法
12. 索引器
索引器(Indexer) 允许一个对象可以像数组一样使用下标的方式来访问。
当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样。您可以使用数组访问运算符 [ ] 来访问该类的的成员。
【1】和属性一样,索引器不用分配内存来存储
【2】索引器和属性都是主要用来访问其他数据成员,他们与这些成员关联,并为他们提供获取和设置访问
【3】属性主要用来表示单独的数据成员,索引器主要用来表示多个数据成员
【4】索引器只能是实列成员,所以不能加static修饰符。
例:方法一(容易理解):
例:方法二(方便灵活):
13. 分部类/分部分类型/分部方法
【1】声明类时加上partial修饰符,可以把类分作多个部分来编写
【2】类的部分申明可以同一文件中,也可以在不同文件中
【3】类(calss)、结构(struct) 、接口(interface)、方法(method)都可以写成部分形式。
【4】部分类型出现的地方比如winfrom,WPF,MVC里的部分视图等
【5】部分方法,一个类里面定义,一个类里面实现,方法必须是私有和无返回值的方法(了解一下就行)
14. 类的继承
【1】继承是面向对象编程的一种基本特性。借助继承,能够定义可重用(继承),可扩展或修改父类的行为的子类。成员被继承的类称为基类。继承基类成员的类称为派生类。
【2】并非所有的基类成员都可以供派生类继承----静态构造函数,实列构造函数,终结器(析构函数)都不能被继承。
【3】派生类不能删除他所继承的任何成员(不能删除基类的成员)
【4】所有类都直接或者间接派生自Object类,Object唯一的非派生类。
【5】C#中类只能单继承,继承的层次没有限制
例:
14.1 屏蔽基类成员(了解)
使用NEW关键字来屏蔽
例:
14.2 使用base关键字访问基类成员。
14.3 派生类转换成基类
【1】派生类的实列由基类的实列加上加上派生类新增的成员组成。派生类的引用指向整个类对象,包括基类部分。
【2】如果有一个派生类对象引用,就可以获取该对象基类的部分引用,通过类型转换运算符()好把派生类转换成基类。
例:
理解图:
14.4 虚方法(virtual)和覆写(重写)方法(overrider)
【1】虚方法可以使基类的引用访问“升至”派生类
【2】当使用基类引用Show()方法时,方法调用被传递到派生类并执行。
【3】虚拟方法和覆写方法必须是相同的可访问性。
【4】方法、属性、索引器、事件都可以声明virtual并被基类进行override。
【5】在什么场景下使用,在派生类有时候会用基类的方法,但有时候有不需要的情况下。
例:
理解图:
14.5 其他类型的virtual成员和override方法
【1】在派生类转换为基类、并且存在多层继承时覆盖方法调用的是哪一个?
答案:在最后派生类里重写方法
例:
14.6 构造方法的执行
【1】要创建对象的基类部分,需要隐式调用基类的某个构造函数做为创建实例过程的一部分。
【2】继承层次链中每个类在执行他自己的构造函数之前执行它的基类构造函数
【3】构造过程=》初始化所有实列成员=》调用基类构造函数=》调用自己的构造函数
14.7 base关键字和显示调用基类的构造函数
【1】默认情况派生类调用基类的无参构造函数。
【2】第一种方式使用base关键字指定使用哪一个基类构造函数 。
【3】this调用自身构造函数,在必须初始化一些数据以及 不想让其他类调用时。
例:(调用基类的构造方法)
例:(this调用自生的构造函数 (this(参数)也可以带参数))
14.8 类的访问修饰符
【1】类有2个访问修饰符public和internal,默认是internal。
【2】在程序集之间做访问控制
14.9 类成员访问修饰符
【1】privat (私有的) 只能在类的内部访问
【2】internal (内部的) 对该程序集内所有类可访问
【3】protected (受保护的)对所有继承该类的类可访问
【4】protected internal (保护内部的) 对所有继承该类或者在该程序集内声明的类可访问。
【5】public (公共的)对任何类可访问
14.10 抽象类
抽象类不能被实例化
【1】抽象类只能被作用其他类的基类、不能创建实列、使用abstract修饰符声明。
【2】抽象类可以可以包含抽象成员和非抽象成员。
【3】抽象类还可以继承。
【4】派生类如果不是抽象类不那么必须使用override关键字实现父类的成员
例:
14.11 抽象成员
【1】抽象成员是指设计为可被覆写(重写)的函数成员。
【2】函数成员前面abstract关键字,不能有实现。
【3】只有函数成员比如方法、属性、事件、索引器、可以声明为抽象成员,字段和常量不可以
【4】只能在抽象类中声明
14.12 密封类
【1】抽象类只能用作基类不能实例化,密封类只能用作独立类,不能被继承。
【2】密封类使用sealed修饰符修饰
【3】密封类的优点
保护知识产权
本本控制--如果一开始设计一个类可能设计不是很完整,后期需要长改动可以设计为密封类。
【4】如何确定是否使用密封类
1- 派生类通过可能获得的潜在好处。
2- 派生类可能采用使他们无法再正常工作或者按预期工作的方式来修改类的可能性。
【5】static class 就是abstract+sealed。
14.13 静态类
static class 就是abstract+sealed。
【1】标记为static的类为静态类。
【2】静态类用于存放不受实列数据影响的数据和函数。
【3】类所有成员都必须是静态的
【4】构造方法只能有一个无参的,而且必须是静态的。
【5】静态类是隐式秘方的,不能继承静态类
14.14 扩展方法
【1】不能或者不想修改原来的类,但又想把方法写成和它相关联。
【2】就是把方法写在其他类里面。
【3】扩展方法是静态的,而且必须是写在静态类里,方法参数第一个必须是this 后面跟着需要太扩展的类型名称
五、表达式和运算符
1.字面量
例:
2. 运算符的优先级和结合性
3. 运算符
3.1 算数运算符
3.2 关系运算符
3.3 逻辑运算符
3.4 位运算符
3.5 赋值运算符
3.6 其他运算符
4. 自定义类型转换
【1】为自己的类和结构定义隐式转换,允许把用户自定义的对象转换成其他类型
【2】隐式转换:编译器自动执行的转换。
【3】显示转换:编译器只在使用显示转换运算符时才执行转换。
5. 运算符重载
六、范型 (代码重用)
1. 范型方法
1.1 用做参数:
使用方法
1.2 用作返回值
1.3 当局部变量使用
2、范型类
创建:
使用:
3、范型约束
class 引用类型的约束
strut 值类型的约束
构造器约束 (多个时一定要放在最后)
引用类型的约束 例:
使用:
值类型的约束 例:
构造器约束 例:
多个约束 - 接口
定义接口:
多个约束:
七、反射 (操作dll文件的一个类库)
怎么使用:
1--查找DLL文件,
2--通过Reflection反射类库里的各种方法来操作DLL文件
八、委托
委托是一种类型《特殊类型,初始化时需要一个方法支持,委托是记录方法的一种类型--调用委托时候也就是调用实例化委托的方法
1、自定义委托
2、范型委托
代码重用可以写出通用代码
例:
定义范型委托:
调用:
3、预定义委托Action和Func
无返回值: Action
有返回值: Func
Action 例:
Func 例:
无参数:
有参数:
四、委托与Lanmdal
Lanmdal:本质上来说就是一个匿名方法;
例如: