C#学习笔记

C#基础

项目创建
最好使用英文命名,可以使用公司名+项目名
一个解决方案中可以有一个或多个项目,可以右击设为启动项目,改变运行时启动的项目
模块的引用
在目录中鼠标右击引用目录 添加引用 搜索自己需要的模块
程序集信息
AssemblyInfo.cs文件,包含文件说明、产品名称、版权等信息,可以直接修改代码更改,也可以双击文件修改。
debug和release
1.debug用来调试程序,可以逐步执行程序用来发现代码中的错误
2.release为发布版,把调试好的程序通过relase编译程序更加轻量,并做了优化

命名空间和类

命名空间

namespace 用来定义命名空间
命名空间通常是用来管理类的方式
一个项目中可以有多个命名空间,一个命名空间中可以有多个类

class 定义类
类:系统类 和 自定义类
类里面用来定义方法

注释

注释:对代码解释说明 被注释的代码 不参与逻辑运算
// 单行注释
/**/ 多行注释
/// 文档注释 多用来解释类或者函数
/// 折叠冗余代码:#Region 和 #EndRegion 不是注释

变量

1.含义:用来存储特定类型的数据格式
2.存储变量的语法: 变量类型 变量名; 变量名=值;
3.变量的使用规则:要先声明再赋值再使用。
4.变量命名规则:1.必须以“字母”或@符号或者_开头,不要以数字开头
5.变量名不要与C#关键字重复
6.小驼峰命名法
7.见名之意
8.变量的作用域内都不能在定义同名的变量
9.变量默认值问题:在函数中 声明的变量是没有默认值的 类中的字段(声明时是有默认值的)

变量声明

int 整型
float 单精度浮点型
double 双精度浮点型
char 字符
string 字符串

常量

1.含义:存储不变的数据 常量的名字要全部大写
常量的定义:const 数据类型 常量的名字

数据类型

数据类型:值类型和引用类型
值类型:整数类型、浮点型、布尔类型、单字符类型、struct(结构)、enum(枚举)
引用类型:字符串类型、类类型、接口、数组、集合、委托
整数类型:byte sbyte int uint long ulong short ushort
浮点类型:单精度和双精度和decimal类型
类型不一样 取值范围不一样 占用的内存不一样 还分为有符号整数和无符号整数
float:单精度浮点数,占4个字节
double:双精度浮点数,占8个字节
decimal:精确的十进制数值,占16个字节
在这里插入图片描述

数据类型转化

数据类型转换
从区间(数字类型)方面进行数据类型转换分为隐式类型转换显式类型转换
隐式类型转换 小区间到大区间
显式类型转换 大区间转小区间 必须明确转换的类型

Parse() 适用于 string转换成其他类型

string str = "123";
int c = int.Parse(str);

TryParse() 与 int.Parse 又较为类似,但它不会产生异常,转换成功返回 true,转换失败返回 false。最后一个参数为输出值,如果转换失败,输出值为 0

string str = "123";
int b ;
bool boo = int.TryParse(str, out b);
string type = boo ? "转换成功" : "转换失败";

Convert类型转换 适合各种类型相互转换 任意类型之间转换 但是转换的内容要符合转换后类型的标准
GetType() 获取数据类型

运算符

算数运算符

“ +、 -、 *、 /、 %、 ++、 – "

关系运算符

" >、 <、 >=、 <=、 ==、 != "

逻辑运算符

“&&(与)、 ||(或)、 !(非)”

循环

		int i = 0 条件的初始变量
        i < length 循环的条件  条件成立循环执行 反之循环终止
        i++ 每次循环结束后 初始变量的自增或自减
        {循环代码}
        for (int i = 0; i < length; i++)
        {
        }

break关键字用于循环体中,终止循环体
continue关键字用于循环体中,终止当次循环,进入下次循环
goto 语句 跳转语句

			LOGIN:
            Console.WriteLine("请输入密码:");
            string passWordStr = Console.ReadLine();
            if (passWordStr == "123456")
            {
                Console.WriteLine("登录成功");
            }
            else
            {
                Console.WriteLine("密码错误");
                goto LOGIN;
            } 

访问修饰符

所有类型和类型成员都具有可访问性级别. 通过访问修饰符的使用来限制或者保护数据的一种形式
public: 同一程序集的其他任何代码或引用该程序集的其他程序集都可以访问该类型或成员。
internal: 同一程序集中的任何代码都可以访问该类型或成员,但其他程序集不可以访问。
private: 同一类和结构的代码可以访问该类型和成员。
protected: 同一类和派生(继承特性)类中的代码可以访问该类型和成员。
protected internal: 同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。
private protected:该类型或成员可以通过从 class 派生的类型访问

C#的默认修饰符

类、结构体的默认修饰符是internal。
类中所有的成员默认修饰符是private。
接口默认修饰符是internal。
接口的成员默认修饰符是public。
枚举类型成员默认修饰符是public。
委托的默认修饰符是internal。

C#方法(函数)

作用:方法是包含一系列语句结构的代码块。方法必须在类或结构中声明
优点:减少代码重复率,方法体现了c#语言的封装性
自定义方法 分为声明方法调用方法
定义方法的格式:访问修饰符 静态或非静态 返回值类型 方法的名字 (形式参数){ 封装的代码 }
静态和非静态定义方法
标识static的方法是静态方法 反之是非静态方法
区别1 :调用方式不一样
静态方法调用使用 (类名.静态方法)
非静态方法调用使用 (类的对象.非静态方法)
1.在本类的静态方法中调用 非静态方法 必须要定义本类的对象 来调用方法

ClassTest classTest = new ClassTest();
classTest.ClassTestMothod5();

2.在本类的非静态方法中调用 静态方法 使用本类类名调用 也可以省略
3.在本类的非静态方法中调用 非静态方法 使用this调用 也可以省略

返回值类型分类

无返回值类型 和 有返回值类型
返回值 代表 当前方法的结果的一个出口
无返回值类型 代表方法的结果 没有出口
返回值类型 代表方法的结果的一个出口 所有的类型 都可以做为返回值类型
return关键字
1.return 在方法中使用
2.return 跳出方法
3.retrun 当前方法结果的出口
4 retrun的结果 要和返回值类型保持一致

参数

参数分为形式参数(形参) 和实际参数(实参)
定义方法中的参数是形参 调用方法中的参数实参
形参的个数是无限个 形参的类型 可以是任意类型 和返回值类型一致

参数传递
  1. 值参数传递:
    (1).参数传递的默认方式
    (2).当调用一个方法时,会为每个值参数创建一个新的存储位置
    (3).当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全
  2. 引用参数传递
    特点:
    1.引用参数是一个对变量的内存位置的引用 不会创建一个新的存储位置
    2.参数关键字 ref
    3.输出参数传递 让方法具有多个返回值结果的参数 ,参数关键字 out

null类型

当我们想要对于一个值类型变量进行 判断 是否 存在时,为了节约内存 可以赋值为null
引用类型可以直接赋值为null,值类型不能直接赋值为null
Null类型是System.Nullable这个struct的类型
值类型赋值null的方法:
1.

Nullable<int> a = null;
int? a = null;

双问号 ??(合并运算符)
作用:用于判断一个变量在为 null 的时候返回一个指定的值

double? num1 = null;
double num2;
num2 = num1 ?? 000;      // num1 如果为空值则返回 000

数组

不可变一维数组

含义:不可变数组是一个存储相同类型元素的固定大小的顺序集合
特点:数组属于引用类型
数组只能包含类型相同的元素
数组通过下标(索引值)标记元素
格式:声明不可变一维数组:datatype[] arrayName;
datatype 用于指定被存储在数组中的元素的类型。
[]指定数组的秩(维度)。秩指定数组的大小。
arrayName 指定数组的名称。

访问数组元素

通过数组的下标(索引值) 从0开始 从左到右 依次递增 1
修改数组元素:

string[] stringArray = {"1","a" ,"w","d","张三","王五"};
stringArray[2] = "z";

遍历数组方式
for
foreach

for (int i = 0; i < stringArray.Length; i++) 
{
	Console.WriteLine(boolArray[i]);
}

foreach (string item in stringArray6)
{
	Console.WriteLine(item);
}

数组越界 是c#中 数组异常 超出数组的最大长度

多维数组

含义:数组嵌套数组形式 一般常用二维数组
二位数组格式:string [,] strArray =new string[数组个数,每个数组中元素个数]
多维数组的遍历:循环嵌套,foreach

交错数组

交错数组 又叫数组类型的数组
含义:交错数组是数组的数组,交错数组是一维数组。
定义交错数组格式:
int[] 数组类型
int[][] 数组类型的数组

int[][] scores;
scores = new int[3][] {new int[2] {1,2},new int[3] {2,3,4},new int[4] { 2,2,1,1} };

Array类

含义:是 C# 中所有数组的基类,它是在 System 命名空间中定义 提供了各种用于数组的属性和方法
Array.CreateInstance() 静态方法 用于创建数组
参数1:设置数组数据类型 typeof(int) 转化值类型 为Type类型对象
参数2:数组的长度

Array intArray = Array.CreateInstance(typeof(int), 5);
Array floatArray  = Array.CreateInstance(typeof(float), 5);

SetValue();
参数1: object 添加的元素
参数2: 数组的索引值

GetValue();
获取指定位置元素

Array.IndexOf();
查找数组元素的索引值 如果存在 返回对应索引值 反之返回 -1

Array.Sort();
从小到大排序 (仅支持一维数组)

Array.Reverse();
数组逆置

可变参数params
1.params是ParamArrayAttribute(参数数组属性)的缩写
2.params解决了C#中不定参数的传递的问题
3.params参数必须定义在参数列表最后面。
4.params必须对一维数组描述
5.params只能在一个方法中定义一个一维数组

String

不可变字符串
含义:
string,引用类型,string类型表示零或更多 Unicode 字符组成的序列,
string 是 .NET Framework 中 String 的别名。
初始化字符串方式

//方式1 字面量创建字符串
            string str1 = "abc";
            string str2  = @"abc";
//方式2
            char[] charArray = new char[5] { 'a','b','c','d','f'};
            string str3 = new string(charArray);
//方式3
             string str4   = string.Format("123");

字符串本质也是单字符的集合,但无法直接修改某个单字符

字符串api

1.Length 获取字符串的长度,即字符串中字符的个数.
2.IndexOf 返回整数,得到指定的字符串在原字符串中第一次出现的位置.
3.LastlndexOf 返回整数,得到指定的字符串在原字符串中最后一次出现的位置.
4.StartsWith 返回布尔型的值,判断某个字符串是否以指定的字符串开头.
5.EndsWith 返回布尔型的值,判断某个字符串是否以指定的字符串结尾.
6. ToLower 返回一个新的字符串,将字符串中的大写字母转换成小写字母.
7. ToUpper 返回一个新的字符串,将字符串中的小写字母转换成大写字母.
8. Trim返回一个新的字符串,不带任何参数时表示将原字符串中前后的空格删除.
9. Remove 返回一个新的字符串,将字符串中指定位置的字符串移除.
10. TrimStart 返回一个新的字符串,将字符串中左侧的空格删除.
11.TrimEnd 返回一个新的字符串,将字符串中右侧的空格删除。
12.PadLeft 返回一个新的字符串,从字符串的左侧填充空格达到指定的字符串长度
13.PadRight 返回一个新的字符串,从字符串的右侧填充空格达到指定的字符串长度.
14.Substring 返回一个新的字符串,用于截取指定的字符串.
15.Insert 返回一个新的字符串,将一个字符串插入到另一个字符串中指定索引的位置.
16.join 字符串数组元素以某个字符串符号分割 然后组成新的字符串
17.Contains 判断字符串是否包含某些子字符串 结果为bool值
18.IsNullOrEmpty 判断字符串是否为空,为空的话返回true。
格式化字符串方式
“+” 拼接
占位符 :Console.WriteLine(“{0}{1}”,str3,intNumber);

int i = 12345;
            Console.WriteLine("{0:C}", i);   //货币
            Console.WriteLine("{0:D}", i);   //十进制数
            Console.WriteLine("{0:E}", i);    //科学技术法
            Console.WriteLine("{0:F}", i);   // 浮点数表示法
            Console.WriteLine("{0:G}", i);   //G或g General 常用格式
            Console.WriteLine("{0:N}", i);   //N或n 用逗号分割千位的数字
//获得当前时间
            DateTime dateTime =  DateTime.Now;
            Console.WriteLine(dateTime.ToString());
            Console.WriteLine("{0:D}", DateTime.Now);   //输出到天
            Console.WriteLine("{0:y}", DateTime.Now);   //输出到月
            Console.WriteLine("{0:m}", DateTime.Now);    //取出是那个月
            Console.WriteLine("{0:T}", DateTime.Now);   // 取长时间到秒
            Console.WriteLine("{0:t}", DateTime.Now);   //取短时间到分
            Console.WriteLine("{0:tt}", DateTime.Now);   //取出是上午还是下午 

模板字符串 $“{变量1},{变量2}”

            string str4 = "abc";
            int intNumber5 = 100;
            float floatNumber5 = 200.0f;
            Console.WriteLine($"{str4}{intNumber5}{floatNumber5}");

进阶

类(属性和字段)

是一个抽象的模板 包含特征或者行为
对象是类具象的事物 具象化类的特征和行为
如何创建类的对象:使用new关键字 new 开辟内存空间为对应类的对象(内存保存的时实例字段和实例方法和实例属性)

People zhangsan = new People();

私有的实例字段无法在类的外部调用
private protected 无法在没有继承关系的类中调用
静态字段在外部调用使用类名
字段默认值为0
const 用类名调,无法在创建之外赋值
readOnly无法在创建之外赋值
定义一个类
1.类要定义在命名空间中或者可以定义在类中嵌套
2.格式:访问修饰符 class 类名 {类的作用域 包含的内容;类的成员}
访问修饰符:默认是internal 可以使用public 在类嵌套可以使用private
类名:大驼峰命名方式 其他参考 标识符用法
类的成员: 成员变量(字段) 成员函数(属性和方法)

特征 (属性和字段)
1.字段
(1)在类中字段也可以叫全局变量
(2)字段是定义在类中方法之外的 局部变量是定义在方法内部的
(3)字段的格式 访问修饰符 数据类型 字段名
(4)字段是有默认值的 值类型默认值为 0 引用类型默认值为null 局部变量没有默认值
(5)在一个类中 不能重复定义字段
(6)字段包含 静态字段和非静态字段(实例字段)
(7)实例字段 随着new对象的创建而创建
(8)静态字段 在类加载的时候创建 且创建一次
只读字段 const 常量关键字 只能在初始化时 赋值 const 包含staitc
readonly 可以在初始化时和构造函数中赋值 readonly 不包含staitc
属性和字段的关系
(1)字段是变量 属性是方法
(2)字段是为类的内部方法,或者方法之间传递数据使用,强调对内使用
属性是对外提供数据访问、本身不保存数据,强调对外使用
(3)字段一般用private修饰,很少用public,属性都是public,从来不用private
字段尽量定义成私有的 如果想访问使用属性
(4)属性可以为私有字段进行扩展
(5)属性可以分别有一个set 和get 方法组成。(或者称为访问器)
(6)字段可以读写均可,也可以用readonly限制为只读,但是不能添加业务逻辑。
属性可以轻松的实现单独读写控制,并且可以添加任意需要的业务逻辑。
语法糖
public int Weight { get; set; }

构造函数

方法–构造函数 特殊的方法
构造函数分为实例构造函数、私有构造函数和静态构造函数
实例构造函数
(1)它主要用于为对象分配存储空间,对数据成员进行初始化.
(2)类默认自带构造函数 如果需要扩展内容 也可以重新定义构造函数
(3)实例构造构造函数的名字必须与类同名
(4)实例构造函数没有返回类型,它可以带参数,也可以不带参数
(5)实例构造方法的访问修饰符通常是public类型的,这样在其他类中都可以创建该类的对象
(6)构造方法是在创建类的对象时被调用的。通常会将一些对类中成员初始化的操作放到构造函数中去完成
(7)构造函数可以重载,从而提供初始化类对象的不同方法
私有构造函数
私有构造函数可用于阻止外部创建类的实例
如果内部调回构造函数 还是可以创建对象
如果想要一个类 真正的没有对象创建 使用静态类
静态类 一般用于工具类
静态类中无法创建构造函数,静态类中的所有成员为静态
静态构造函数
1.静态构造函数既没有访问修饰符,也没有参数。
2.创建第一个类实例或任何静态成员被引用时,自动调用静态构造函数来初始化类
3.一个类只能有一个静态构造函数。 如果没定义 系统默认有 反之只能定义无参静态构造函数
4.无参数的实例构造函数可以与静态构造函数共存。尽管参数列表相同,但一个属于类,一个属于实例,所以不会冲突
5.在类创建时 系统自动调用一次静态构造函数

析构函数

1.垃圾回收程序最终销毁对象之前调用的方法,该方法称为析构函数
2.析构函数,没有返回值,且不带任何参数。
3.在对象删除前,用它来做一些清理工作 比如 一些和类相关的数据
强制开启回收 立即回收内存 调用析构函数 GC.Collect();

~MyClass()
        {
            Console.WriteLine("对象被释放了");
        }
封装

将类的某些信息隐藏在类内部(private),不允许外部程序直接访问,
而是通过该类提供的公共属性(public)来实现对隐藏信息的操作和访问
封装的好处
1、隐藏类的实现细节
2、只能通过规定属性访问数据
3、方便加入控制语句
4、方便修改实现

继承

1.一个类继承另一个类 其中被继承的类(父类 超类 基类) 继承的类(子类 派生类)
2.继承关系建立后 子类拥有父类的属性和方法 反之父类不继承子类属性和方法。
3. 继承的作用:解决类与类直接 属性或者方法重复的问题
4 .C#中类与类之间是单继承关系 利用接口实现多继承(后续讲)
5. 继承的格式 A类(子类) : B类(父类)
6. 创建子类对象时,系统默认先调用父类构造方法,然后再调用子类构造方法
7.当父类有有参构造方法时,如果子类有构造方法(无参或有参),要求父类必须有一个无参构造方法。
8.转型:子类可以赋值给父类,但是父类不能赋值给子类
9.覆盖:在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,编译后会提示要求使用New关键字 ,使用base 可以调用父类覆盖的方法
base关键字 代表父类的对象
10.Object 是所有引用类型的基类
如果类没有明确的继承关系,默认继承Object类

多态

含义:即一个接口,多个功能,同一种操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
体现多态的功能有:重写、重载、抽象类、接口
重写 必然发生在基类和派生类中,其类函数用virtual修饰,派生类用override修饰
重写的目的:父类的方法功能 不能满足于子类需求时
父类允许子类覆盖叫重写 virtual允许子类覆盖 这种方法叫虚方法
重载函数名相同,参数类型或者顺序不同和个数有关,与返回类型无关
覆盖,在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,编译后会提示要求使用New关键字

抽象类

1.关键字 abstract
2.不能被实例化 不能创建对象
3.抽象类可以包括抽象方法,或者普通方法
4.抽象方法和属性只能被定义 ,在子类中实现
5.继承抽象类的非抽象类,必须包含全部已继承的抽象方法和访问器的实现
6.通过包含使用 override 修饰符的属性声明,可在派生类中重写抽象类 方法和属性

接口

接口定义:所有类继承接口时应遵循的语法合同 (接口定义那些功能 继承的类就要实现功能)
作用:用接口可以使程序更加清晰和条理化
1.接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的​
2.接口只包含了成员的声明(方法 属性声明)
3.不允许声明成员上的修饰符,即使是pubilc都不行,因为接口成员总是公有的
4.不能声明为虚拟和静态的成员
5.接口中定义的成员需要类继承来进行实现,类的继承关系要在接口继承之前
6.接口也可以继承接口
7.一个类可以继承多个接口(接口就是c#实现多继承的方式)

接口和抽象类的区别和相同点
相同点:不能实例对象,都可以被继承,都可以给继承类提供成员模板
不同点:接口只能有成员定义,不能定义静态和虚拟的成员,抽象类也可以包含成员的实现,
接口可以实现多继承,抽象类只能单继承

密封类

1.密封类可以用来限制继承性
2.声明密封类时需要使用sealed关键字
3.密封类和普通类一样都可以定义属性和方法
4.密封类不能作为基类被继承,但它可以继承别的类或接口
5.密封类可以实例化对象,系统中String 就是密封类
6.在密封类中不能声明受保护成员或虚成员

泛型

允许我们延迟编写类或方法中的数据类型,直到真正使用时确定类型的一种规范
1.可以创建自己的泛型接口、泛型类、泛型方法、泛型集合,泛型事件和泛型委托
2.泛型的格式:结构<泛型的名称T> 在定义泛型时T通常用作变量类型名称。但实际上 T 可以用任何有效名称代替
3.泛型方法在定义时提供泛型的类型,在调用方法时 提供具体的延迟编写的类型
4.泛型无法直接使用运算符,比如 + - < > 等,但是能使用Object中的属性和方法

 //泛型方法的定义
        public void MyClassMothod<T>(T a)
        {
            Console.WriteLine(a);
        }
        public T MyClassMothod1<T>(T a, T b)
        {
            Console.WriteLine(a);
            Console.WriteLine(b);
            return a;
        }

泛型类 default解决默认值问题

public class MyClass1<T> 
    {
        private T _age;
        public T Age { get; set; }
        public T MyClass1Mothod() {
            //解决T 泛型的 默认值问题
            T a = default(T);
            return  a; 
        }
    }

泛型接口

interface IMyInterFace<T>{
    }

装箱、拆箱

泛型可以提供代码性能,避免了装箱和拆箱 Object类型做为参数时 所有的实参都会进行类型转换
值类型转换成引用类型。这个转换称为装箱。
引用类型 转换成 值类型相反的过程称为拆箱

int number = 10;
// 装箱  
object obj = number;
// 拆箱  
number = (int)obj;

泛型约束
泛型约束:泛型中的数据约束可以指定泛型类型的范围

public class MyClass<T, K, V, W, X> 
        where T : struct 
        where K : class 
        where V : IMyInterface 
        where W : K
        where X : MyClassTest
{
}

集合

1.不可变数组

int[] intArray =new int[8] { 1, 2, 3, 4, 5, 6, 7, 8, };

ArrayList 可变数组
1.ArrayList大小是按照其中存储的数据来动态扩充与收缩的
2.ArrayList可以很方便地进行数据的添加插入删除
3.ArrayList 可以存储任意类型
4.ArrayList在存储和读取数据时 会进行装箱和拆箱 影响程序性能
创建对象

ArrayList arrayList = new ArrayList();

Add() 末尾添加元素 返回值为添加元素的索引值
AddRange() 范围添加元素 可以直接添加 继承于ICollection的集合的对象
Insert() 插入元素、参数1 索引值、参数2 插入的元素
RemoveAt() 按索引值删除元素
Remove() 按元素删除元素 删除匹配第一个元素
RemoveRange() 范围删除元素 、参数1 删除开始的索引值、参数2 删除的长度
Clear() 清空元素

List 泛型集合
List 与其他数组的比较:
List与不可变数组(Array类)比较类似,都用于存放类型相同的元素。
List与可变数组(ArrayList)比较类似 元素长度不固定。

//创建泛型集合对象  存储的元素类型为string
List<string> list = new List<string>();

Dictionary字典类
1.Dictionary 没有索引值 只有key/Value
2.key/Value都可以是任何类型
3.Dictionary是可变长度的集合
4.Dictionary是泛型的集合 定义对象时 要指定 key/Value的类型
5.通过key值查询value 且key值是唯一

//创建对象
Dictionary<string,int> keyValuePairs = new Dictionary<string, int>();
//添加元素
keyValuePairs.Add("0", 10);
keyValuePairs.Add("1", 20);
//取值
Console.WriteLine(keyValuePairs["0"]);
//修改值
keyValuePairs["0"] = 30;

ContainsKey() 查询key是否存在字典中 有返回true 反之返回false

结构体

1.结构体是值类型 关键字Struct
2.类是引用类型
3.引用类型均隐式继承 System.Object ,而值类型均隐式继承System.ValueType
4.所有的整数类型和浮点数类型 本质都是 一个结构体
5.结构可带有方法、字段、属性、运算符,委托和事件。
6.结构可实现一个或多个接口 但是不能继承其他类 和结构体
7.结构不支持被其他类继承。
8.结构类似与密封类 不能使用virtual 或 protected
结构体的默认修饰符是internal
如果定义有参构造函数 必须在 构造函数内部 初始化所有 字段和属性

类和结构总结:
  1. 类和结构实际上都是创建对象的模板, 每个对象都包含数据,并提供了处理和访问数据的方法
  2. 类是引用类型 对象存于堆中 可以通过GC管理内存 结构是值类型 对象存于栈中 、
  3. 结构不能被继承 也不能继承其他类 但是能继承接口
  4. 结构和类 都能使用new 创建对象 但是结构也可以不使用
  5. 结构作为方法参数 默认是值传递 类类型默认是引用传递

枚举

作用:枚举能够使代码更清晰,描述一组整数值 使数字更具有具体意义
1.枚举是值类型
2.枚举类型使用 enum 关键字声明的。
3.枚举是一组整型常量 默认是从 0开始 也可以自己定义范围
4.枚举使用enum关键字来声明,与类同级。枚举本身可以有修饰符,但枚举的成员始终是公共的,不能有访问修饰符。枚举本身的修饰符仅能使用public和internal。
5.枚举都是隐式密封的,不允许作为基类派生子类

委托和事件

委托

1.委托就是把方法(函数)变成一种引用类型的方式
2.委托 关键字 delegate
3.委托分为定义委托和使用委托
定义委托
1.定义委托和定义类一样可在命名空间中定义,也可以像变量一样在类的内部定义,
3.委托可以使用修饰符:public,private,protected等 一般使用public 委托的默认修饰符是internal。
4.委托可以根据不同类型的方法(有参无参 有返回值 无返回值等)定义 多个委托类型

delegate void MyDelegate(int x);  //定义了一个 无返回值有一个int类型参数的委托
使用 Action和Func委托

方法的返回类型和名字千千万万,无法对每个方法都去定义对应的委托,
.net为了方便使用委托,定义了两个泛型委托。
Action委托表示一个void返回类型的方法
Func委托表示一个带返回类型的方法
如果有参数 返回值类型在最后
委托的多播
1.方法的类型相同
2.同时执行
3.委托对象利用+=方式 完成多播的使用 -=取消多播操作

事件

1.事件基于委托的,可以为任何一种委托提供一种发布\订阅机制。(类似委托多播)
2.使用event关键字将一个委托类型定义为事件 事件就是委托的一个对象

public delegate void BoilHandle(int x);//声明关于事件的委托
public event  BoilHandle boilHandle;

事件 使用 += 和-= 来完成委托的多播的操作

Heater heater = new Heater();
heater.boilHandle += Heater1;
heater.boilHandle += Heater2;
heater.boilHandle -= Heater1;
普通匿名函数

1.针对委托的使用
2.可以快捷的使委托实例化。
3.不建议再使用匿名函数,C#3.0后使用lambda表达式替代普通匿名函数
4.格式: 委托对象 = delegate (){};
lambda
lambda表达式
1.普通匿名函数的升级版本 (箭头函数)
2.比普通匿名函数更为简洁,数据类型可以不用写

//无参无返回值匿名函数
Action action = () => { };

对象初始化器
对象初始化器 --是重载有参构造函数的语法糖

 People people = new People() { ID = 10,Name ="张三"};
运算符重载

1.含义
是对已有的运算符重新定义新的运算规则,以适应不同的数据类型
关键字:operator

public class People {
    public int ID {get;set;}
    public string Name { get;set;}
    //People对于+的重载方法
    public static People operator +(People people, People people1)
    {
        return new People() { ID = people.ID + people1.ID, Name = people.Name + people1.Name };
    }
    public static bool operator !(People stu1)
    {
        if (stu1.ID >= 18)
        {
            return true;
        }
        else {
            return false;
        }  
    }
}
C#异常处理

C# 中的异常类主要继承与 System.Exception 类
引起异常的语句 系统默认会抛出异常信息

 //有异常会输出catch中的内容
 try
 {
     // 引起异常的语句
     int[] array = { 1, 2 };
     array[3] = 10;
 }
 catch (SystemException e)
 {
     Console.WriteLine("有异常出现:{0}", e.Message);
 }
 finally 
 {
     Console.WriteLine("有没有异常都执行");
 }
预处理器指令

预处理器指令指导编译器在实际编译开始之前对信息进行预处理。

C# 预处理器指令列表
 
下表列出了 C# 中可用的预处理器指令:
预处理器指令	描述
#define	它用于定义一系列成为符号的字符。
#undef	它用于取消定义符号。
#if	它用于测试符号是否为真。
#else	它用于创建复合条件指令,与 #if 一起使用。
#elif	它用于创建复合条件指令。
#endif	指定一个条件指令的结束。
#line	它可以让您修改编译器的行数以及(可选地)输出错误和警告的文件名。
#error	它允许从代码的指定位置生成一个错误。
#warning	它允许从代码的指定位置生成一级警告。
#region	它可以让您在使用 Visual Studio Code Editor 的大纲特性时,指定一个可展开或折叠的代码块。
#endregion	它标识着 #region 块的结束。
File 文件的创建与读写

创建文件

string path = @"D:\myFile.txt";
FileStream fileStream = File.Create(path);  // 创建
fileStream.Close(); // 关闭

写入文件

StreamWriter streamWriter = new StreamWriter(path);    
streamWriter.WriteLine("ABC");
streamWriter.WriteLine("DDD"); // 换行
streamWriter.Write("HAHAH"); // 不换行
streamWriter.Write("ABVV");
streamWriter.Close();

读取文件

StreamReader sr = new StreamReader(path, Encoding.UTF8);
string content = sr.ReadToEnd();
Console.WriteLine(content);
sr.Close();

判断是否存在此文件,不

private static void FileDataAppend() {
    string path = @"D:\myFile.txt";
    if (!File.Exists(path))  //检查文件是否存在
    {
        FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);  //创建
        StreamWriter sw = new StreamWriter(fs);
        sw.WriteLine("input text");  //写入内容,自定义

        sw.Close();
        fs.Close();
    }
    else
    {
        FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write);  //追加写入
        StreamWriter sw = new StreamWriter(fs);
        sw.WriteLine("567");  //写入内容,自定义

        sw.Close();
        fs.Close();
    }
}

进程和线程

1.默认程序只有一个主线程 代码执行也是默认在主线程执行
如果主线程遇到了 繁重的任务 可以开辟分线程来执行任务 从而不影响主线程的执行
2.C# 到5.0 之前一共有4种创建线程的方式:
Thread 自己创建的独立的线程, 优先级高,需要使用者自己管理。

//创建线程1
//创建分线程 要执行的任务(委托)
ThreadStart childref = new ThreadStart(ProgramMothod);
//创建分线程实例对象
Thread childThread = new Thread(childref);
childThread.Name = "分线程1";
//执行分线程
childThread.Start();

//创建线程2

 //创建线程2
 Thread thread2 = new Thread(() => {
     Console.WriteLine("繁重的任务2");
 });
 thread2.Start();

//创建线程3 线程休眠

Thread thread3 = new Thread(() =>
{
    Console.WriteLine("繁重的任务3");
    //线程休眠  单位毫秒
    Thread.Sleep(2000);
    Console.WriteLine("繁重的任务33");
});
thread3.Start();

Abort() :手动销毁线程
Join():线程阻塞

设置当前主线程的名字:

Thread.CurrentThread.Name = “主线程”;

线程抢占

如果两个线程同时对某个资源进行同时访问就可能出现 线程抢占

static readonly object locker = new object(); //线程锁对象

//lock线程锁 如果某个线程进入方法内时 会锁定方法  
//直到当前线程执行完毕此方法时 ,后续的线程才能进入方法执行代码

//(标识对象)
lock (locker)
{
	//执行的代码
}
线程池

ThreadPool 线程池
线程和线程池都是进行多线程操作的方式,
线程池是用来保存线程的一个容器,
在程序创建线程来执行任务的时候线程池才会初始化一个线程,
线程在执行完毕之后并不会被销毁,而是被挂起等待下一个任务的到来被激活执行任务,
当线程池里的线程不够用的时候会新实例化一个线程来执行,线程池里的线程会被反复利用。

ThreadPool 使用线程池 操作线程

//ThreadPool 使用线程池 操作线程
WaitCallback waitCallback = new WaitCallback(ProgramMothod);
//在分线程中执行方法  
ThreadPool.QueueUserWorkItem(waitCallback);

//简写1
WaitCallback waitCallback1 = arg => Console.WriteLine("dosomething1");
ThreadPool.QueueUserWorkItem(waitCallback1);

//简写2
ThreadPool.QueueUserWorkItem(e => {
    Console.WriteLine("dosomething2");
});
// 方式二:
//QueueUserWorkItem 接收两个参数,
//第一个参数是WaitCallback 委托类型,
//第二个参数是object对象,用于传递给委托函数的参数
ThreadPool.QueueUserWorkItem(e =>
{ 
    People p = e as People;
    Console.WriteLine(p.Age);
}, new People() { Age = 10 });

ThreadPool 如何阻塞主线程

ManualResetEvent mreset = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(e =>
{
    Thread.Sleep(2000);
    Console.WriteLine("dosomething3");
    mreset.Set();
});
//阻塞主线程 等待分线程完成后 执行mreset.Set()后执行后续代码
mreset.WaitOne();
Console.WriteLine("阻塞主线程");

Task

Task的任务控制:Task比threadPool优点就是任务控制,很好的控制task的执行顺序,让多个task有序的执行

Task.Wait 就是等待任务执行完成之后 执行后续代码
Task.WaitAll 待所有的任务都执行完成:
Task.WaitAny 等待任何一个任务完成就继续向下执行
Task.ContinueWith 第一个Task完成后自动启动下一个Task,实现Task的延续
CancellationTokenSource 通过cancellation的tokens来取消一个Task。

开启task分线程

Task task = Task.Run(() => { });

Task的线程取消

//1.初始化线程取消类
CancellationTokenSource tokenSource = new CancellationTokenSource();
//2.获取线程取消标记
CancellationToken token = tokenSource.Token;

//  var 的作用再c#和js代表任意类型  但是c#和js不一样  c# 是强类型语言 再赋值之前类型确定 js是弱类型语言  在赋值之后类型确定
//  var a = tokenSource.Token; 

//使用线程取消标记 取消线程
Task.Run(() => {
    for (var i = 0; i < 1000; i++)
    {
        Thread.Sleep(1000);
        Console.WriteLine(i);

        //是否执行取消方法 如果取消  为true  反之为 false
        // tokenSource.Cancel(); 作用就是让token.IsCancellationRequested 为true
        //token.IsCancellationRequested 默认值为false
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("取消请求已发出");
            //return 才是真正结束线程方式 
            return;
        }
    }

},token);

Console.WriteLine("123");
//取消线程方法
tokenSource.Cancel();
//取消线程  tokenSource.Cancel()后  把token.IsCancellationRequested 为true 时  调用的方法
token.Register(() =>
{
    Console.WriteLine("令牌已经取消");
});
Console.WriteLine("456");
同步 异步async/await

如何通过使用async/await 完成异步编程
1.async 必须修饰方法 被修饰的方法 表示是一个异步方法
2.async 和await必须连用 如果不使用await 那么这个方法还是同步方法
3.async 描述的方法 的返回值类型必须是void 或者是task 或者task
4.await 描述的也是方法 但是必须是使用线程(task)的方法
5.async方法在执行的时候,开始是以同步的方式执行,直到遇到await关键字,
从await关键字开始,C#会另起一个线程执行await后面的代码。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值