一.类(Class)
1. 定义:类是一种数据类型的蓝图,它规定了在这个对象上可以执行什么操作。
2. 实例化:类不能直接使用,必须先实例化后才能使用,实例化就是一个创建对象的过程。C#使用new关键字来实例化对象。
- 个人理解:类就是一种概念,当这个概念被实现的时候,它就是一个有实体的类,就是对象。
3. 静态(static):一种数据类型的约束
- 静态成员可以是成员变量也可以是成员函数
- 静态成员不可以通过对象调用,只能通过类来调用
- 个人理解:因为被修饰为静态后就是这个类的唯一,这个类只有这一个变量或者函数,所以的对象都公用这个。
4. 构造函数和析构函数
- 构造函数: 访问修饰符 类名(如果没有构造函数会默认生成无参数的空构造函数)
- 析构函数:~类名
5. 访问修饰符(指是否能够访问(找)的到)
- Public:任何公用成员可以被外部类访问。
- Private:只有同一个类的函数可以访问它的私有成员。
- Protected:该类内部和继承类中可以访问。
- internal:同一个程序集的对象可以访问。(同一个命名空间内)
- Protected internal:3和4的并集,符合任意一条都可以访问
- 范围比较
private < internal/protected < protected internal < public
6. 命名空间(static):一种数据类型的约束
namespace 命名空间名字{
class c1{ fucton1(){} }
}
class c1{ fucton1(){} }
//调用
命名空间名字.c1.fucton1() //调用第一个函数
c1.fucton1() //调用第二个函数
同一个命名空间内不能重名,没有写在命名空间内的默认是全局的,在命名空间内的类要引入命名空间再调用
7. 面向对象
-
继承
- 一个类可以获得另一个类的全部(数据成员和成员函数)就是类的继承。
- 这个已有的类(被继承的类)被称为的基类,这个新的类(继承基类的类)被称为派生类。
- 继承就是将公用的属性或方法抽离到父类的过程。这个思维称之为面向对象。
- 子类不可以访问父类中的Private的变量(感觉上继承是像里面又多了一个类,继承来的不完全是自己的)。
-
封装
-
“把一个或多个项目封闭在一个物理的或逻辑的包中”,通俗一点的解释就是,隐藏技术细节,仅暴露外部调用者关心的接口
-
virtual 是虚拟的含义,表示这些成员将会在继承后从写其中的内容,但virtual不能修饰使用static修饰的成员
//修饰属性 访问修饰符 virtual 数据类型 属性名 //修饰方法 访问修饰符 virtual 返回值类型 方法名 {}
-
override,是在子类中重写父类中的方法,两个函数的函数特征(函数名、参数类型与个数)相同。用于扩展或修改继承的方法、属性、索引器或事件的抽象或虚拟实现。提供从基类继承的成员的新实现,而通过override声明重写的方法称为基方法。
//修饰方法 基方法的访问修饰符 override 基方法的返回值类型 基方法的方法名 {}
-
-
多态
- 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。(因为函数被重载重写等原因)
- 多态就是同一个接口使用不同的实例而执行不同操作。
- 静态多态(编译时编译器能确定的)
-比如说 派生类经过重写基类的方法后在对应的对象中调用该方法。会根据容器来确定方法的内容。 - 动态多态(运行时多态,只有运行时才能确定的方法)
-比如说 一个基类有多个派生类但是每个派生类都重写了基类的方法,用基类才存放派生类的对象(只可以子类赋值给父类不可以反过来),然后调用该方法,会根据容器来确定方法的内容。
8. 覆盖和重载
- 覆盖:发生在 继承关系中,通过
virtual
和override
两个关键字来实现。(函数名已经函数参数是一模一样的) ,即可实现覆盖。 - 重载:发生在 任何关系中,只要保证函数名称一致,函数参数不一致(带参数和不太参数,带参数顺序不一致,带参数个数不一致),即可实现重载。
9. this和base
- this:指的是访问当前类的成员
- base:指的是访问基类的成员
10. 只读变量和常量
-
const
:在类内声明的const常量- 外部访问时,必须通过类名进行访问,但不可修改值
- 只能在声明时初始化,不允许在任何其他地方对其初始化(包括构造函数)
- 在某种程度,被const修饰的变量(常量),不可变值
-
readonly
:在类内声明的readonly常量- readonly const ,不可以共同修饰一个类型(基本数据类型+自定义数据类型)
- readonly修饰的类型,只能被类的实例化进行访问,但不可修改值
- readonly的初始化,只能发生在构造函数或者声明中
-
可以通过访问修饰符构成的语法块,来实现类似外部只读的效果 get set
//public修饰get private修饰set public int value1 {get;private set;}
-
value赋值
//把值放在另一个变量里面 不知道为什么要这样写 public int value1; public int value2 { get{ return value1; } set{ value1 = value; } }
11. 静态类
-
类可以声明为
static
,这将变成一个静态类,不得被继承,特点是仅包含静态成员或常量。 -
静态类的特点:
-
不能被实例化,意味着不能使用
new
关键字创建静态类实例。 -
仅包含静态成员或常量,内部成员必须是静态成员/常量
-
不能被继承,无法作为基类派生
-
静态类不允许有实例构造函数,只允许纯在一个静态构造函数,(静态类的静态构造函数,经测试发现,并不会执行)
-
静态构造函数:
- 静态构造函数不需要增加访问修饰符(因为是被系统调用的,不让加修饰符)
- 静态构造函数无论多少实例都只被调用一次,而且是只被系统自动调用一次
-
-
静态类一般用于工具类
12. 抽象类
-
类可以声明为
abstract
,这将变成一个抽象类。 -
抽象类的特点:
- 不能被实例化,意味着不能使用
new
关键字创建实例。 - 可只提供部分函数实现,也可仅声明抽象函数。
- 支持构造函数,静态构造函数和普通构造函数
- 静态构造函数只执行一次,但是其他构造函数则根据不同实例,分别再次调用。
- 允许
virtual
虚函数 和override
重写 - 若函数声明为
abstract
,则不允许包含函数体; 子类必须实现父类的该方法。
- 不能被实例化,意味着不能使用
-
抽象类是提炼出了一些类共有的属性或函数接口的组织,为子类提供设计思想,配合多态多用于代码架构设计。
13. 密封类
-
类可以声明为
sealed
,这将变成一个密封类。 -
密封类的特点:
- 不能被继承,但可以继承别的类或接口;
- 密封类不能声明为抽象类既
sealed abstract
不能共存 - 密封类内的函数,不允许增加
sealed
关键字 - 密封类可以正常继承常见类(普通类、抽象类)、接口
-
密封类一般用于防止重写某些类或接口影响功能的稳定。
14. 泛型类
-
类名后面可以添加 <T1、T2、T3…>,这将变成一个泛型类。泛型 T1、T2、T3可以通过
where
关键字来限定类型。 -
泛型类的特点:
- 在声明时可以不指定具体类型,但是在 new实例化时必须指定T类型
- 可指定泛型类型约束
- 如果子类也是泛型的,那么继承的时候可以不指定具体类型
-
泛型约束注意的点 .NET含有以下五种泛型约束:
where T : class
T必须是一个类where T : struct
T必须是一个结构类型where T : new()
T必须要有一个无参数的构造函数where T : NameOfBaseClass
T必须继承名为NameOfBaseClass的类where T : NameOfInterface
T必须实现名为NameOfInterface
-
例子:
//定义 普通 public class Class1<T>{ private T[] array; } //调用 Class1<int> myClass = new Class1<int>(); //定义 泛型可以是自定义的类 public class ClassType { public int a; } public class Class2<T>{} //public class Class2<T> where T:ClassType {} //用约束 //调用 Class2<ClassType> myClass = new Class2<ClassType>(); //定义 多个泛型 public class BaseParent<T,X> {} //定义 多个泛型的继承 如果不修改父类的泛型那子类也要有相应的泛型 public class Son<T,X> :BaseParent<T,X> {} //定义 多个泛型的继承 如果修改父类的泛型 public class Son:BaseParent<int,string> {} //定义 子类可以有更多泛型 public class Son<T,X,Y,A>: BaseParent<T,X> {} //定义 子类可以有父类没有的泛型 public class Son<X,Y> :BaseParent<int,string> {} //定义 方法泛型 方法泛型的作用于仅限于方法内 类的则是整个类里面 public class Son:BaseParent<int,string> { public void Show<X>( X A ) {...} } //调用 Son son = new Son(); son.Show<string>("show your text");
-
泛型类一般用于处理一组功能一样,仅类型不同的任务时。
14. 接口
-
interface + name
这将变成一个接口 -
接口的特点:
- 接口值声明接口函数,不包含实现
- 接口函数访问修饰符必须是
public
,不能将函数的声明改为私有的 - 接口成员函数的定义是派生类的责任,接口只提供派生类应遵循的标准结构
- 接口不可以被实例化,既不可new
- 接口可以继承其他接口,允许单一继承也允许多重继承(类只允许继承单个类,但是可以同时继承多个接口,只要实现了接口的函数就行)
-
约束一些行为规范时,可以用接口
15. 接口和抽象类之间的区别
-
共同点:
- 都可以被继承,但是不可以被实例化
- 都支持只声明函数,不包含实现(抽象类函数不加修饰符可以包含实现)
- 派生类必须实现未实现的方法
-
不同点:
抽象类 | 接口 | |
---|---|---|
变量 | 可以声明变量 | 不允许声明变量 |
构造函数 | 不允许构建函数 | 允许拥有构造函数 |
函数实现 | 函数不是抽象的情况下可以实现 | 不可以实现 |
访问修饰符 | 默认是private 函数前面若是abstract 那访问修饰符也不能是private ; 但是非abstract 声明的函数是允许private 或者 protected 的 | 默认是public 不允许改变为private |
是否多重继承 | 抽象类只能被单一继承 | 接口可被多重继承 |
性质 | 抽象类是一个不完整的类,需要进一步细化 | 接口是一个行为规范 |
作用 | 抽象类更多的是定义一系列紧密相关的类间 | 接口大多数是关系疏松但都实现某一功能的类中 |
16. struct 结构体
-
struct + name { ... }
便声明了一个结构体 -
结构体是值类型数据结构,它使得一个单一变量可以存储各种数据类型的相关数据。
-
结构体的特点:
- 结构体可带有方法、字段、索引、属性、运算符方法和事件
- 结构体可定义构造函数,但不能定义析构函数。不能定义无参构造函数,无参构造函数是自动定义的,且不能被改变
- 与类不同,结构不能继承其他的结构和类,但是可实现一个或多个接口。
- 结构不能作为其他结构或类的基础结构。
- 结构成员不能指定为
abstract、virtual 或 protected
- 结构体不能通过
new
来实现
17. struct 和 class 的异同
-
相同点:
- 都支持静态构造函数
- 都支持自定义函数
- 结构体和类对于
const
修饰的变量的使用方法是一样的 - 结构体变量和类对象必须进行初始化才可以访问函数
-
不同点:
struct | class | |
---|---|---|
构造函数 | 结构体不允许定义无参构造函数,只允许定义有参构造函数 | 类是都可以 |
析构函数 | 不允许定义析构函数 | 类是可以的 |
函数的修饰符 | 结构体函数不允许声明为 virtual 虚函数;结构体函数不允许声明为protected 受保护的函数 | 类是可以的 |
类型修饰符 | 结构体类型不允许声明为abstract | 类是可以的 |
关于变量-普通变量 | 结构体声明的全局普通变量(不带修饰符的),不能在声明时直接赋值,只能在构造函数里面赋值 | 类是哪里都可以的 |
关于变量-readonly | 结构体声明的全局readonly 变量,只能在构造函数里面赋值 | 类是哪里都可以的 |
关于继承 | 结构体之间不可以互相继承 | 类与类之间是可以继承的(sealed 密封类除外) |
访问变量 | 结构体访问成员变量,给变量赋值,就可直接访问 | 类必须实例化对象才可以访问 |
new | 结构体属于值类型,结构体的new并不会在堆上分配内存,仅仅是调用结构体的构造函数初始化而已 | 类属于引用类型,类的new会在堆上分配内容,而且也会调用类的构造函数进行初始化 |