笔记相关–C#入门到进阶

前记:自己学C#时候的一些笔记,内容可能较多,在vscode里面写的,3000行左右。

---------------------------目录-------------------------
面向对象–封装
类和对象
成员变量和访问修饰符
成员方法
构造函数和析构函数
成员属性
索引器
静态成员
静态类和静态构造函数
拓展方法
运算符重载
内部类和分部类
面向对象–继承
继承的基本规则
里氏替换原则
继承中的构造函数
万物之父和装箱拆箱
密封类
面向对象–多态
Vob
抽象类和抽象方法
接口
密封方法
面向对象关联知识点
命名空间
万物之父中的方法
String
StringBuilder
结构体和类的区别
构造体和接口的区别

面向对象的三大特征:
封装+继承+多态
封装:用程序语言形容对象
继承:复用封装对象的代码,复用现成代码
多态:同样行为的不同表现,儿子继承父亲的基因但是有不同的行为表现
面向对象的七大原则:
开闭原则、依赖倒转原则、里氏替换原则、单一职责原则、接口隔离原则、合成复用原则、迪米特原则

命名:帕斯卡命名法:首字母大写
驼峰命名法
new分配的空间在堆上,如果没有用new则只是在栈上分配了一个堆的空引用

构造函数:
特别注意点:
class Person
{
public string name;
public int age;
public Person():this.(“Haoye”,10)
{
name="";
age=0;
}
public Person(string _name):this()
{
name=_name;
}
public Person(string _name,int _age):this(_name)
{
name=_name;
age=_age;
}
}

析构函数:
当引用类型的堆内存呗回收时,会调用该函数;
对于需要手动管理内存的语言(如c++),需要在析构函数中做一些内存回收处理
但是c#中存在自动垃圾回收的机制GC
基本语法:
~类名{ }

析构函数时当垃圾真正被回收的时候才会调用该函数

垃圾回收机制:
垃圾回收的过程是遍历堆上(Heap)的动态分配的所有对象
通过识别他们是否被引用来确定哪些对象是垃圾,哪些对象仍要被使用
所谓的垃圾就是没有被任何变量、对象引用的内容
垃圾就是需要被回收释放

垃圾回收算法:引用计数(Reference Counting):标记清除(Mark Sweep):标记整理(Mark Compact):复制整合(Copy Collection):注意:Gc只负责堆(Heap)中的垃圾回收引用类型都是存在堆上(Heap)的,所以它的分配和释放都是通过垃圾回收机制来管理的栈(Stack)上的内存是由系统自动管理的值类型是在栈(Stack)中分配的内存,他们有自己的生命周期,不用对他们进行管理,系统会自动分配和释放c#中内存回收机制的大概原理:0代内存 1代内存 2代内存代的概念:代的是垃圾回收机制使用的一种算法(分代算法)新分配的对象都会被配置在第0代内存中每次分配都可能会进行垃圾回收以释放内存(0代内存满时)在一次内存回收过程开始时,垃圾回收器会认为堆中全是垃圾,会进行以下两步:1.标记对象,从根(静态字段、方法参数)开始检查引用对象,标记后为可达对象,未标记为不可达对象2.不可达对象就会被认为是垃圾3.搬迁对象压缩堆(挂起执行托管代码线程),释放未标记的对象,搬迁可达对象,修改引用地址大对象总会被认为是第二代内存,目的是减少性能消耗,提高性能不会对大对象进行搬迁压缩, 85000字节(83 kb)以上的对象成为大对象GC的人为主动调用是在loading条中调用

-----博主:mx
成员属性
成员属性的基本语法
class Person
{
private string name;
private int age;
private int money
public string name
{
get{
//可以在返回之前添加一些逻辑规则,可以进行加密处理
//意味着这个属性可以就iu哦谢内容
return name;
}
set{
//可以在设置之前添加一些逻辑规则
//value 关键字 用于表示 外部传入的值
name=value;
}
}
public int money
{
get{
//加密处理
return money;
}
set{
if (value<0)
{
value=0;
}
money=value;
}
}
}

成员属性中get和set前可以加访问修饰符注意:1.默认不加,会使用属性声明时的访问权限2.加的访问修饰符要低于属性的访问权限3.不能让get和set的访问权限都低于属性的权限get和set可以只有一个自动属性作用:外部能得不能改的特征如果类中有一个特征是只希望外部能得不能改的,有没有什么特殊处理的,那么可以直接使用自动属性public int Height{//会自动生成一个int型数值来给他//没有在get和set中写逻辑的需求或者想法get;private set;}总结:
1.成员属性作用:一般用来保护成员变量
2.get中需要return内容;set中value表示传入的内容
3.get和set语句块中可以加逻辑处理
4.get和set可以加访问修饰符,但要按照一定的规则进行添加
5.get和set可以只有一个
6.get和set可以加访问修饰符,但是要按照一定的规则进行添加
7.自动属性是属性语句块中只有get和set,一般用于外部能得不能改的情况

索引器
索引器基本概念:
让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观、更容易编写
索引器语法:
访问修饰符 返回值 this[参数类型 参数名,参数类型 参数名…]
{
内部的写法和规则 与索引器相同
get{}
set{}
}
例子:
class Person
{
private string name;
private int age;
private Person[] friends;
public Person this[int index]
{
get{ return friends[index];}
set{ friends[index]=value;}
}
}

索引器中可以写逻辑:在get和set中可以写一些逻辑索引器重载:class Person{private string name;private int age;private Person[] friends;private int[,] array;public int this[int i,int j]{get{return array[i,j];}set{array[i,j]=value;}}public Person this[int index]{get{ return friends[index];}set{ friends[index]=value;}}}总结:索引器对我们来说的主要作用:可以让我们以中括号的形式范围自定义类中的元素,规则自己定义,访问时和数组一样比较适用于在类中有数组变量时使用,可以方便的访问和进行逻辑处理

静态成员:
概念:用static修饰的成员变量、方法、属性等,成为静态成员
生命周期:和程序同生共死
程序运行后就会一直存在内存中,直到程序结束后才会释放,因此静态成员具有唯一性
注意:
1.静态函数中不能直接使用非静态成员
2.非静态函数中可以直接使用静态成员
const和static的不同点:
1.const必须初始化不能被修改,static没有这个规则
2.const只能修饰变量,static可以修饰很多
3.const不能写在访问修饰符前面,一定是写在变量声明前面,static没有这个

静态类和静态构造函数:
静态类
静态构造函数:
概念:在构造函数前加上static修饰
特点:
1.静态类和普通类都可以有
2.不能使用访问修饰符
3.不能有参数
4.只会自动调用一次

    作用:在静态构造函数中初始化,静态变量使用:1.静态类中的静态构造函数2.普通类中的静态构造函数class Test{public static int testInt=200;static Test(){Console.WriteLine("静态构造");}public Test(){Console.WriteLine("普通构造");}}

拓展方法
基本概念:
概念:为现有非静态变量类型添加新方法
作用:
1.提升程序拓展性
2.不需要在对象中重新写方法
3.不需要继承来添加方法
4.为别人封装的类型写额外的方法
特点:
1.一定是写在静态类中
2.一定是个静态函数
3.第一个参数为拓展目标
4.第一个参数用this修饰

基本语法:访问修饰符 static 返回值 函数名(this 拓展类名 参数名,参数类型 参数名,参数类型 参数名......)实例:static class Tools{//为int拓展了一个成员方法//成员方法是需要实例化对象后才能使用//value代表使用该方法的实例化对象public static void  SpeakValue(this int value){Console.WriteLine("为Int拓展的方法"+value);}public static void  SpeakStringInfo(this string str,string str2,string str3){Console.WriteLine("为string拓展的方法"+str);Console.WriteLine("传的参数"+str2+str3);}//为自定义的类拓展方法//注意如果拓展方法名与原有方法相同,则拓展失败会使用原方法public static int Func3(this Test t){Console.WriteLine("为test拓展的方法"+str);return 0;}}使用:int i=10;i.SpeakValue();

-----博主:mx
封装——运算符重载
基本概念:
概念: 让自定义类和结构体可以使用运算符
使用关键字:operator
特点:
1.一定是一个公共的静态方法
2.返回值写在operator前
3.逻辑处理自定义
作用: 让自定义类和结构体可以使用运算符
注意:
1.条件运算符需要成对实现
2.一个符号可以多个重载
3.不能使用ref和out

基本语法:public static 返回类型 operator 运算符(参数列表)//二元运算符的参数类型必须包含至少一个类型
实例:class Point{public int x;public int y;public static Point operator +(Point p1,Point p2){Point p=new Point();p.x=p1.x+p2.x;p.y=p1.y+p2.y;return p;}}
可重载和不氪重载的运算符:逻辑运算符:可:!  不可:&& ||位运算符:可:| & ^ ~ << >>条件运算符:返回值一般是bool值,也可以是其他相关符号必须配对出现可:> < <= >= ==不可以重载的符:逻辑与&& 逻辑或||索引符[]强转运算符()特殊运算符点 .  三目运算符?: 赋值符号=

内部类和分部类:
内部类:
概念:在一个类中再声明一个类
特点:使用时要用包裹着点出自己
作用: 亲密关系的表现
注意:访问修饰符作用很大
class Person
{
public int age;
public string name;
public Body body;
public class Body
{
Arm leftarm;
Arm rightarm;
class Arm
{

            }}}class Program{static void Main(string[] args){Person p=new Person();Person.Body body =new Person.Body();}}
分部类:概念:把一个类分成几部分声明关键字:partial作用:1.分部描述一个类2.增加程序的拓展性注意:1.分部类可以写在多个脚本中2.分部类的访问修饰符要一致3.分布类中不能有重复成员示例:+++++partial class Student{public bool sex;public string name;分部方法:partial void Speak();}partial class Student{public int  number;partial void Speak(string str){}}分部方法:概念:将方法的声明和实现分离特点:1.不能加访问修饰符,默认私有2.只能在分布类中声明3.返回值只能是void4.可以有参数但是不用out关键字局限性较大

----------------------------------------面向对象–继承------------------------------------

继承的基本概念
基本概念:
一个类A继承一个类B
类A将会继承类B的所有成员
A类将拥有B类的说有特征和行为

    被继承的类称为父类、基类、超类继承的类被称为子类、派生类子类可以有自己的特征和行为特点:1.单根性:子类只能由一个父类2.传递性:子类可以间接继承父类的父类基本语法:class 类名:被继承的类名{}访问修饰符的影响:public 公共的  ,内外部访问private 私有的 ,内部访问protected 保护的 ,内部和子类访问internal 内部的, 只有在同一个程序集的文件中,内部类型或者是成员才可以访问
子类和父类的同名成员:c#中允许子类存在和父类同名的成员,但是极不建议认识

-----博主:mx

里氏替换原则
基本概念:
里氏替换原则是面向对象七大原则中最重要的原则
概念:
任何父类出现的地方,子类都可以代替
重点:
语法表现–父类容器装子类对象,因为子类对象包含了父类的所有内容
作用:
方便进行对象的储存和管理

基本实现:class GameObject{}class Player:GameObject{public void PlayerATK{Console.WriteLine("玩家攻击");}}class  Boss:GameObject{public void PlayerATK{Console.WriteLine("玩家攻击");}}class Monster:GameObject{public void PlayerATK{Console.WriteLine("玩家攻击");}}class Program{static void Main(string[] args){Console.WriteLine("里氏替换原则\n");GameObject player=new Player();GameObject monster=new Monster();GameObject boss=new  Boss();GameObject[] objects=new GameObject[] {new Player(),new Monster(),new Boss()};}}is和as:基本概念:is:判断一个对象是否为指定类对象返回值:bool 是为真,不是为假as:将一个对象转换为指定类对象返回值:指定类型对象   成功返回指定类型对象,失败返回null基本语法:类对象 is 类名   该语句块会有一个bool返回值 true和false类对象 as 类名   该语句块会有一个对象返回值 对象和null示例:if(player is Player){Player p= player as Player;p.PlayerATK();}

继承中的构造函数
基本概念:
特点:当申明一个子类对象时,先执行父类的构造函数、再执行子类的构造函数
继承中构造函数的执行顺序:
父类的父类的构造函数 > 父类的构造函数 > 子类的构造函数
父类的无参构造函数:
默认调用父类的无参构造函数,如果没有声明无参构造函数就会报错
class Father
{
public Father()
{

        }public Father(int i){Console.WriteLine("Father构造");}}class Son:Father{//使用base向父类的构造函数传参并调用public Son(int i):base(i){Console.WriteLine("Son的一个参数构造");}public Son(int i,string str):this(i){Console.WriteLine("Son的两个参数构造");}}通过base调用指定父类构造:上面的示例

装箱拆箱
万物之父:
关键字:object
概念:object是所有类型的基类,他说一个类(引用类型)
作用:
1.可以利用里氏替换远测,用object容器装所有的对象
2.可以用来表示不确定的类型,作为函数参数类型

万物之父的使用:引用类型:object o=new Son();用is as 来判断和转换即可if(o is Son){(o as Son).Speak();}值类型object o2=1f;用强转float i=(float)o2;特殊的string类型object str ="123123";string str2=str as string;object arr=new int[10];int[] ar=arr as int[];装箱拆箱:发生条件:用object存值类型(装箱)用object转换为值类型(拆箱)装箱:把值类型用引用类型存储,栈内存会迁移到堆内存拆箱::把引用类型存储的值类型取出来,堆内存会迁移到栈内存中好处:不确定类型时可以方便参数存储和传递坏处:存在内存迁移,增加性能消耗不是不用,尽量少用

密封类:
基本概念:
是使用sealed密封关键字修饰的类
作用:让类无法再被继承
示例:
class Father
{

    }sealed class Son:Father{}
作用: 1.在面向对象程序设计中,密封类的主要作用就是不允许最底层子类被继承2.可以保证程序的规范性、安全性(目前来说可能作用不大,但是当制作复杂系统或者程序框架时,就能慢慢感受)

----------------------------------------面向对象–多态------------------------------------

多态Vob
多态的概念:让继承同一父类的子类们,在执行相同方法时有不同的表现(状态)
主要目的:同一父类的对象,执行相同行为(方法)有不同的表现
解决的问题:让同一个对象有唯一的行为特征
多态的实现:
编译时的函数重载
v:virtual(虚函数)
o:override(重写)
b:base(父类)
示例:
public GameObject
{
public string name;
public GameObject(string name)
{
this.name=name;
}
//虚函数:可以被子类重写
public virtual void Atk()
{
Console.WriteLine(“游戏对象进行攻击”);
}
}
class player:GameObject
{
public player(string name):base(name)
{

        }public override void Atk(){//base的作用://代表父类,可以通过base来保留父类的行为//base.Atk();Console.WriteLine("玩家对象进行攻击");}}class Monster:GameObject{public Monster(string name):base(name){}public override void Atk(){Console.WriteLine("怪物对象进行攻击");}}class Program{string void Main(string[] args){Console.WriteLine("多态Vob");GameObject p=new Player("主角");p.Atk();(p as Player).Atk();GameObject m=new Monster("小怪物");m.Atk();(m as Monster).Atk();}}
总结:多态:让同一类型的对象,执行相同行为时有不同的表现解决的问题:让同一个对象有唯一的行为特征vob:v:virtual 虚函数o:override 重写b:base 父类v和o一定时结合使用的,来实现多态b是否使用根据实际需求,保留父类行为

多态-抽象类和抽象方法
抽象类:
概念:
被抽象关键字abstract修饰的类
特点:
1.不能被实例化
2.可以包含抽象方法
3.继承抽象类必须重写其中的抽象方法

抽象函数(抽象方法):又叫纯虚方法用abstract关键字修饰的方法特点:1.只能在抽象类中声明2.没有方法体3.不能是私有的4.击沉后必须实现,用override重写
示例:abstract class Thing{//抽象类中,封装的所有知识点都可以在其中书写public string name;//可以在抽象类中书写抽象方法}class Water:Thing{}class Program{string void Main(string[] args){Console.WriteLine("抽象类和抽象方法");//抽象类不能被实例化//Thing t=new Thing();//但是,可以遵循里氏替换原则,用父类容器装子类Thing t=new Water();}}
总结:抽象类:被abstract修饰的类,不能被实例化,可以包含抽象方法抽象方法:没有方法体的纯虚方法,继承后必须实现的方法注意:1.如何选择普通类还是抽象类2.不希望被实例化的对象,相对比较抽象的类可以用抽象类3.父类重点行为不需要被实现的,只希望子类去定义具体规则的可以选择抽象类然后使用其中的抽象方法来定义规则作用:整体框架设计时会使用

多态-接口
接口的概念:
概念:
接口是行为的抽象规范
它也是一种自定义类型
关键字:interface
接口的声明规范:
1.不包含成员变量
2.只包含方法、属性、索引器、时间
3.成员不能被实现
4.成员可以不用写访问修饰符,不能是私有的
5.接口不能继承类,但是可以继承另一个接口
接口的使用规范:
1.类可以继承多个接口
2.类继承接口后,必须实现接口中的所有成员
特点:
1.它和类的声明类似
2.接口是用来继承的
3.接口不能被实例化,但是可以作为容器存储对象
接口的声明:
接口关键字:interface
语法:
interface 接口名
{

        }一句话记忆:接口时抽象行为的“基类”接口命名规范,帕斯卡前面加一个Iinterface IFly{void Fly();string name{get;set;}int this[int index]{get;set;} event Action doSomthing;}接口的使用:接口是用来继承:1.类可以继承1个基类,n个接口2.继承了接口后,必须实现其中的内容,并且必须是public的3.实现接口的函数,可以假virtual再在子类里重写4.接口也遵循里氏替换原则class Animal{}class Person:Animal ,IFly{public void Fly(){}public string name{get;set;}public int this[int index]{get;set;} public  event Action doSomthing;}
接口可以继承接口:接口继承接口时,不需要实现带类继承接口后,类需要去实现所有的内容
显示实现接口:当一个类继承两个接口但是接口中存在着同名方法时,注意:显示实现接口时,不能写访问修饰符示例:interface IAtk(){void Atk();}interface ISurperatk(){void Atk();}class Player :IAtk ,ISurperatk{void IAtk.Atk(){}void ISurperatk.Atk(){}}
总结:继承类:是对象间的继承,包括特征行为等等继承接口:是行为间的继承,继承接口的行为规范,按照行为规范去实现内容由于接口也是遵循里氏替换原则,所以可以用接口容器装对象那么久可以实现,装载各种毫无关系但是却有相同行为的对象注意:1.接口值包含:成员方法、属性、索引器、事件,并且都不实现,且没有访问修饰符2.可以继承多个接口,但是只能继承一个类3.接口可以继承接口,相当于在进行行为合并,带子类继承是再去实现具体的行为4.接口可以被显示实现,主要用于实现不同接口中的同名函数的不同表现5.实现接口的方法,可以假virtual关键字,之后子类再重写

多态-密封方法
基本概念:
概念:
用密封关键字sealed修饰的重写函数
作用:
让虚方法或者抽象方法之后不再被重写
特点:
和override一起出现
示例:
public class Animal
{
public string name;
public abstract void Eat();
public virtual void Speak()
{
Console.WriteLine(“叫”);
}
}
class Person:Animal
{
public sealed override void Eat()
{

        }public sealed override void Speak(){}}
总结:  1.密封方法,可以让虚方法和抽象方法不能再被子类重写2.特点:一定是和override一起出现

-----博主:mx
----------------------------------------面向对象关联知识点------------------------------------

命名空间
基本概念:
概念:
命名空间是用来组织和重用代码的,并且可以复用单词
作用:
就像一个工具包,类就像是一件一件的工具,都是声明在命名空间中的

命名空间中的使用:基本语法:namespace 命名空间名{类类}示例:namespace MyGame{class GameObject{}}namespace MyGame{class Player:GameObject{}}不同命名空间中允许有同名类namespace MyGame2{class GameObject{}}命名空间可以包裹命名空间namespace MyGame3{namespace  UI{class UI{class Image{} }}namespace  Game{class Game{class Image{} }}}
关于修饰类的访问修饰符public   ---命名空间中的类默认为publicinternal ---只能在该程序集中是Yoonabstract ---抽象类sealed   ---密封类partial  ---分部类总结:1.命名空间是个工具包,用来管理类的2.不同命名空间中,可以有同名类3.不同命名空间中相互使用,需要using引用命名空间 或者 指明出处4.命名空间可以包裹命名空间

万物之父中的方法
object中的静态方法
静态方法 Equals 判断两个对象是否相等
最终的判断权,交给左侧对象的Equals方法
不管值类型引用类型都会按照左侧对象Equals方法的规则进行比较
(引用类型比较是比较两个对象是否是同一个地址)

        Test t=new Test();Test t2=t;Console.WriteLine(object.Equals(t,t2));静态方法RefenceEquals比较两个对象是否相同的引用,主要是用来比较引用类型的对象值类型对象返回值始终是falseConsole.WriteLine(object.RefenceEquals(t,t2));object中的成员方法普通方法GetType该方法在反射相关知识中使非常重要的方法该方法的主要作用就是获取对象运行时的类型Type通过Type结合反射相关知识点可以做许多关于对象的操作Test t=new Test();Type type=t.GetType();普通方法MemberwiseClone该方法用于获取对象的浅拷贝对象,口语化的意识就是返回一个新对象,但是新对象中的引用变量会和老对象中一致,但是值类型对象不一样 会是新的class Test{public int  i=1;public Test2 t2=new Test2();public Test Clone(){return MemberwiseClone() as Test;}}class Test2{public int i=2;}class TestClone{Test t=new Test();Type type=t.GetType();Test t2=t.Clone();Console.WriteLine("克隆对象后");Console.WriteLine("t.i = " + t.i);Console.WriteLine("t.t2.i = " + t.t2.i);Console.WriteLine("t2.i = " + t2.i);Console.WriteLine("t2.t2.i = " + t2.t2.i);t2.i=20;t2.t2.i=21;Console.WriteLine("t.i = " + t.i);Console.WriteLine("t.t2.i = " + t.t2.i);Console.WriteLine("t2.i = " + t2.i);Console.WriteLine("t2.t2.i = " + t2.t2.i);}
object中的虚方法虚方法Equals默认实现还是比较两者是否为同一个引用,机相当于RefenceEquals但是微软在所有值类型的基类System.ValueType中重写了该方法,用来比较值相等我们也可以重写该方法,定义自己的比较相等的规则虚方法GetHashCode该方法时获取对象的哈希码(一种通过算法算出的,表示对象的唯一编码,不同对象哈希码又可以一样,具体值根据哈希算法决定)我们可以通过重写该函数来定义对象的哈希码算法,正常情况下,我们使用的极少,基本不用。虚方法ToString该方法用于返回当前对象代表的字符串,我们可以重写它定义我们自己的对象转字符串规则该方法非常常用,当我们调用打印方法时,默认使用的就是对象的ToString方法打印出来的内容总结:1.虚方法:ToString 转换成字符串(可以通过重写来自定义字符串转换规则)2.成员方法:GetType 反射相关3.成员方法:MemberwiseClone 浅拷贝4.虚方法:Equals 判断相等(可以通过重写来自定义判断相等的规则)

string
字符串指定位置获取
字符串本质是char数组

    转化为char数组char[] chars=str.ToCharArray();字符串拼接str=strin1.Format("{0}{1}",1,3333);正向查找字符的位置string str="好耶针布戳";int index=str.IndexOf("耶");反向查找指定字符串位置string str="好耶针布戳好耶";int index=str.LastIndexOf("耶");移除指定位置后的字符string str="好耶针布戳好耶";string str2= str.Remove(4);Console.WriteLine(str2);可以执行两个参数进行移除参数一:开始位置参数二:字符个数str2=str.Remove(1,1);Console.WriteLine(str);替换指定字符串string str="好耶针布戳好耶";string str2= str.Replace("好耶","ky");Console.WriteLine(str2);大小写转换string str="asdasdTSDAHsaddas";string str2= str.ToUpper;Console.WriteLine(str2);str2=str.ToLower();Console.WriteLine(str2);字符串截取string str="好耶针布戳好耶";//截取从指定位置开始之后的字符串string str2= str.Substring(2);Console.WriteLine(str2);//参数一:开始位置//参数二:指定个数//不会自动帮助你判断是否越界,需要自己判断str2= str.Substring(2,3);Console.WriteLine(str2);字符串切割string str="1,2,3,4,5";string[] strs=str.Split(',');for(int i=0;i<strs.Length;i++){Console.WriteLine(strs[i]);}

StringBuilder
知识回顾string
string是特殊的引用
每次重新赋值或者是拼接时会重新分配内存空间
如果一个字符串经常改变会非常浪费空间

基本概念概念:C#提供的一个用于处理字符串的公共类主要解决的问题:修改字符串而不是创建新的对象,需要频繁修改和拼接的字符串可以使用它,可以提升性能使用前需要引用命名空间初始化-直接指明内容StringBuilder str=new StringBuilder("123123123");Console.WriteLine(str);容量StringBuilder存在一个容量问题,每次往里增加时,会自动扩容获取容量Console.WriteLine(str.Capacity);获取字符长度Console.WriteLine(str.Length);增删改查替换增:str.Append("4444");Console.WriteLine(str);Console.WriteLine(str.Length);Console.WriteLine(str.Capacity);str.AppendFormat("{0}{1}",100,999);Console.WriteLine(str);Console.WriteLine(str.Length);Console.WriteLine(str.Capacity);插入:str.Insert(0,"123");Console.WriteLine(str);删:str.Remove(0,10);Console.WriteLine(str);清空:str.Clear();Console.WriteLine(str);查:Console.WriteLine(str[1]);改:Console.WriteLine(str[1]);str[0]='A';替换:str.Replace("1","haoye");Console.WriteLine(str);重新赋值 StringBuilderstr.Clear();str.Append("123123");Console.WriteLine(str);判断://必须使用Equals,无法使用== 会报错if(str.Equals("123123")){Console.WriteLine("相等");}

【【【【【【面试常见】】】】】】】

结构体和类的区别
区别概述:
结构体和类的最大区别是在存储空间上,结构体是值类型,而类是引用类型
因此结构体是存储在栈上,而类是存储在堆上

    结构体和类在使用上类似,结构体甚至可以用面向对象的思想类形容一类对象结构体具备着面向对象思想中封装的特性,但是它不具备继承和多态的特性,因此大大减少了它的使用频率由于结构体不具备继承的特性,所以他不能够使用protected保护访问修饰符细节区别:1.结构体是值类型,而类是引用类型2.结构体存储在栈中,而类存储在堆中3.结构体成员不能使用protected访问修饰符,而类可以4.结构体成员变量声明不能指定初始值,而类可以5.结构体不能声明无参的构造函数,而类可以6.结构体声明有参数的构造函数后,无参构造不会被顶掉7.结构体不能声明析构函数,而类可以8.结构体需要在构造函数中初始化所有成员变量,而类随意9.结构体不能被继承,而类可以10.结构体不能被静态static修饰(不存在静态构造体),而类可以11.结构体不能在自己内部声明和自己一样的结构体变量,而类可以结构体的特别之处结构体可以继承结构因为接口是行为的抽象如何选择结构体和类1.想要使用继承和多态是,直接淘汰结构体,比如玩家、怪物等等2.对象是数据集合时,优先考虑结构体,比如位置、坐标等等3.从值类型和引用类型赋值时的区别上去考虑,比如经常被赋值传递的对象,并且改变赋值对象,原对象不想跟着变化时,就用结构体,比如坐标、向量、旋转等等

抽象类和接口的区别
知识回顾:
抽象类和抽象方法
abstract修饰的类和方法
抽象类不能被实例化
抽象方法只能在抽象类中声明,是个纯虚方法,必须在子类中实现

    接口interface自定义类型是行为的抽象不包含成员变量仅包含方法、属性、索引器  ;  事件,成员都不能实现,建议不写访问修饰符,默认public相同点1.都可以被继承2.都不能直接实例化3.都可以包含方法声明4.子类必须实现未实现的方法5.都遵循里氏替换原则区别1.抽象类中可以有构造函数,而接口中不能2.抽象类只能被单一继承,而接口可以继承多个3.抽象类可以有成员变量,而接口中不能4.抽象类可以声明成员方法,虚方法,抽象方法,静态方法;而接口只能声明没有实现的抽象方法5.抽象类方法可以使用访问修饰符,而接口中建议不写,默认public如何旋转抽象类和接口表示对象的用抽象类,表示行为的拓展用接口不同对象拥有的共同行为,我们往往可以使用接口来实现举个例子:动物是一类对象,自然会优先想到抽象类;而飞翔是一个行为,我们自然会选择接口

目前学习的总结
面向对象–封装
类和对象
成员变量和访问修饰符
成员方法
构造函数和析构函数
成员属性
索引器
静态成员
静态类和静态构造函数
拓展方法
运算符重载
内部类和分部类

面向对象–继承
继承的基本规则
里氏替换原则
继承中的构造函数
万物之父和装箱拆箱
密封类

面向对象–多态
Vob
抽象类和抽象方法
接口
密封方法

面向对象关联知识点
命名空间
万物之父中的方法
String
StringBuilder
结构体和类的区别
构造体和接口的区别

-----博主:mx
--------------------------------C#进阶部分学习----------------------------------
哈希表Hashtable
Hashtable的本质
Hashtable(又称为散列表),是基于键的哈希代码组织起来的键值对
它的主要作用是提高数据的查询效率
使用键来访问集合中的元素

申明必须:需要引用命名空间System.CollectionsHashtable hashtable=new Hashtable();
增删改查增Hashtable.Add(1,"123");Hashtable.Add(2,"1234");Hashtable.Add("123",1);Hashtable.Add("123",12);Hashtable.Add(true,false);Hashtable.Add(false,true);//注意:不能出现相同的键删1.只能通过键去删除hashtable.Remove(1);2.删除一个不存在的键,没反应hashtable.Remove(2);3.或者直接清空hashtable.Clear();查1.通过键查看值,如果找不到则返回空2.查看是否存在根据键检测if(hashtable.Contains(2)){Console.WriteLine("存在键为2的键值对");}if(hashtable.ContainsKey(2)){Console.WriteLine("存在键为2的键值对");}根据值检测if(hashtable.ContainsValue(12)){Console.WriteLine("存在值为12的键值对");}改//只能改 键对应的值hashtable[1]=100.5f;Console.WriteLine(hashtable[1]);遍历得到键值对 对数Console.WriteLine(hashtable.Count);遍历所有键foreach(object item in hashtable.Keys){Console.WriteLine("键:"+item);Console.WriteLine("值:"+hashtable[item]);}遍历所有值foreach(object item in hashtable.Values){Console.WriteLine("值:"+item);}键值对一起遍历foreach(DictionaryEntry item in hashtable.Values){Console.WriteLine("键:"+item.Key+"值:"+item.Value);}迭代器遍历法IDictionaryEnumerator myEnumerator =hashtable.GetEnumerator();bool flag=myEnumerator.MoveNext();while(flag){Console.WriteLine("键:"+myEnumerator.Key+"值:"+myEnumerator.Value);flag=myEnumerator.MoveNext();}装箱拆箱本质是一个可以自动扩容的object数组由于用万物之父来存储数据,自然存在装箱拆箱当往其中进行值类型存储时就是在装箱当将值类型对象取出来转换使用时,就存在拆箱

泛型
泛型是什么
泛型实现了类型参数化,达到代码重用的目的
通过类型参数来实现同一份代码上操作多种类型
泛型相当于类型占位符
定义类或者方法时使用替代符代表变量类型
当真正使用类或者方法时再具体指定类型

泛型分类泛型类和泛型接口基本语法: class 类名<泛型占位字母>interface 接口名<泛型占位字母>泛型函数:基本语法:函数名<泛型占位字母>(参数列表)注意:泛型占位字母可以有多个,用逗号隔开泛型类和接口:class TestClass<T>{public T value;}class TestClass<T,T1,T2,T3>{public T value;public T1 value;public T2 value;public T3 value;}泛型方法普通类中的泛型方法class Test2{public void TestFun<T>(T value){Console.WriteLine(value);}public void TestFun<T>(){//泛型类型在里面做一些逻辑处理T t=default(T);}public void TestFun<T>(String v){return default(T);}public void TestFun<T,T1,T2,T3>(T value,T1 value1,T2 value2,T3 value3){}}  泛型类中的泛型方法class Test2<T>{public T value;public void TestFun<M>(M k){}//这个不是泛型方法,因为T是泛型类声明的时候就指定了,在使用这个函数的时候,我们不能再去动态的变化了public void TestFun(T t){}}class Program{static void Main(string[] args){Console.WriteLine("泛型");TestClass<int> t=new TestClass<int>();t.value=10;Console.WriteLine(t.value);TestClass<string> t2=new TestClass<string>();t2.value="123456";Console.WriteLine(t2.value);Test2 tt=new Test2();tt.TestFun<string>("123567");Test2<int> tt2=new Test2<int>();tt2.TestFun(10);tt2.TestFun<string>("123");tt2.TestFun<float>(1.2f);tt2.TestFun(20);}}泛型的作用1.不同的类型对象的相同逻辑处理可以选择泛型2.使用泛型可以一定程度避免装箱拆箱举例:优化ArrayList总结:1.声明泛型时,它只是一个类型的占位符2.泛型真正起作用的时候,是在使用它的时候3.泛型占位字符可以有n个用逗号分开4.泛型占位字母一般是大写字母5.不确定泛型类型时,获取默认值,可以用default(占位字符)6.看到<>包裹的字母,那肯定是泛型

泛型约束
什么是泛型约束:
让泛型的类型有一定的限制
关键字:where
泛型约束一共有6种
1.值类型 where 泛型字母:struct
2.引用类型 where 泛型字母:class
3.存在无参公共构造函数 where 泛型字母:new()
4.某个类本身或者其派生类 where 泛型字母:类名
5.某个接口的派生类型 where 泛型字母:接口名
6.另一个泛型类型本身或者派生类型 where 泛型字母:另一个泛型字母

各类泛型约束讲解值类型约束class Test<T> where T:struct{public T value;public void TestFun<K>(K v) where K : struct{}}  引用类型约束class Test<T> where T:class{public T value;public void TestFun<K>(K v) where K : class{}}无参公共构造函数约束//必须无参//必须是公共的class Test<T> where T:new(){public T value;public void TestFun<K>(K v) where K : new(){}}class Test1{public Test1(){}}class Test2{public Test2(int a){}}类约束//必须是类本身或者是其子类(派生类)class Test4<T> where T: Test1{public T value;public void TestFun<K k> where K:Test1{}}class Test3:Test1{}接口约束//必须是接口派生出来的类型interface IFly{}class Test3:IFly{}class Test4<T> where T: IFly{public T value;public void TestFun<K k> where K:IFly{}}另一个泛型约束class Test4<T,U> where T: U{public T value;public void TestFun<K,V> where K:V{}}约束的组合使用class Test7<T> where T:class,new(){}多个泛型有约束class Test8<T,K> where T:class ,new() where K:struct{}总结:泛型约束:让类型有一定限制classstructnew()类名接口名另一个泛型字母注意:1.可以组合使用2.多个泛型约束,用where连接即可

LinkedList
基本介绍:
LinkedList是一个C#编写好的类
本质是一个可变类型的泛型双向链表

声明:需要引用命名空间   using System.Collection.Generic链表对象  需要掌握两个类一个是链表本身,一个是链表节点类LinkedListNode增删改查:LinkedList<int> linkedList1=new LinkedList<int>();增:1.在链表尾部添加元素linkedList1.AddLast(10);2.在链表头部添加元素linkedList1.AddFirst(20);3.在某一个节点之后要指定节点,先得得到一个节点LinkedListNode<int> n=linkedList1.Find(20);linkedList1.AddAfter(n,15);4.在某一个节点之前添加一个节点要指定节点,先得得到一个节点linkedList1.AddBefore(n,11);删:1.移除头节点linkedList1.RemoveFirst();2.移除尾节点linkedList1.RemoveLast();3.移除指定节点无法通过位置直接移除linkedList1.Remove();4.清空linkedList1.Clear();查:1.头节点LinkedListNode<int> first=linkedList1.First();2.尾节点LinkedListNode<int> last=linkedList1.Last;3.找到指定值的节点无法直接通过下标获取中间元素只有遍历查找指定位置元素LinkedListNode<int> node=linkedList1.Find(3);Console.WriteLine(node.Value);node = linkedList1.Find(5);Console.WriteLine(node);4.判断是否存在if(linkedList1.Contains(1)){Console.WriteLine("链表中存在1");}改:要得再改, 得到节点,再改变其中的值Console.WriteLine(linkedList1.First.Value);linkedList1.First.Value=10;Console.WriteLine(linkedList1.First.value);遍历foreach遍历foreach(int item in linkedList1){Console.WriteLine(item);}通过节点遍历从头到尾Console.WriteLine("&&&&&&&&&&&&&&&&&");LinkedListNode<int> nowNode =linkedList1.First;while(nowNode!=null){Console.WriteLine(nowNode.Value);nowNode=nowNode.Next;}从尾到头Console.WriteLine("&&&&&&&&&&&&&&&&&");LinkedListNode<int> nowNode =linkedList1.Last;while(nowNode!=null){Console.WriteLine(nowNode.Value);nowNode=nowNode.Previous;}

委托
委托基本概念
委托是函数的容器
可以理解为表示函数的变量类型
用来储存、传递函数
委托本质是一个类,用来定义函数的类型(返回值和参数类型)
不同的函数必须对应和各自"格式"一致的委托

委托基本语法关键字:delegate语法:访问修饰符  delegate  返回值  委托名(参数列表);写在哪里?可以声明在namespace和class语句块中更多的写在namespace中简单记忆委托语法就是在函数声明语法前面加一个delegate关键字
定义自定义委托范文修饰符默认不屑,为public ,在别的命名空间中也能使用private 其他命名空间不能用了一般使用public//申明了一个可以用来存储无参无返回值函数的容器//这里只是定义了规则,并没有使用//委托规则的声明,是不能重名的(同一语句块中)//表示用来装载或者传递,返回值int,有一个int参数的函数的委托,容器规则delegate void MyFun()delegate int MyFun2(int  a);
使用定义好的委托委托变量是函数的容器委托常用在:1.作为类成员2.作为函数的参数class Test{public MyFun fun;public Myfun2 fun2;public void TestFun(MyFun fun,Myfun2 fun2){//可以先处理一些别的逻辑,当这些逻辑处理完了,再执行传入的函数int i=1;i+=1;i*=2;this.fun+=fun;this.fun2+=fun2;}//增public void AddFun(MyFun fun,Myfun2 fun2){this.fun+=fun;this.fun2+=fun;}//删public void AddFun(MyFun fun,Myfun2 fun2){this.fun-=fun;this.fun2-=fun;}}委托变量可以存储多个函数(多播委托)系统定义好的委托//使用系统自带的委托 ,需要引用using System;Action action=fun;action+=fun3;action();//可以指定返回值类型的 泛型委托 Func<string> funcstring=fun4;//可以传n个参数的 系统提供了1到16个参数的委托,直接用就行了Action<int ,string > action =fun6;//可以传n个参数的,并且有返回值的,系统也提供了16个参数的委托Func<int ,int > func2=Func;
class Program
{static void Main(string[] args){Console.WriteLine("委托");MyFun f=new MyFun(fun);Console.WriteLine("委托");f.Invoke();MyFun f2=Fun;Console.WriteLine("委托");f2();MyFun2 f3=fun2;Console.WriteLine(f3(1));MyFun2 f4=new MyFun2(fun2);Console.WriteLine(f4.Invoke(3));Test t=new Test(fun().,fun2);Console.WriteLine(“*****************”);Myfun2 ff=null;ff+=fun;ff+=fun;ff();t.AddFun(fun,fun2);t.fun();t.fun2();//移除指定函数ff-=fun;//多减,不会报错ff-=fun;ff();//清空指定容器ff=null;if(ff!=null){ff();}}static void fun(){Console.WriteLine("123456");}static int fun2(int value){Console.WriteLine("haoye"+value);return value;}static void fun3(){}static string fun4(){return "123";}static void fun6(int i,string str){}
}总结:简单理解:委托就是装载、传递函数的容器而已可以委托变量来存储函数或者传递函数的系统其实已经可以提供了很多委托给我们用Action:没有返回值,参数提供了0~16个委托给我们用Func:有返回值,参数提供了0~16个委托给我们用

事件
事件是什么;
事件是基于委托的存在
事件是委托的安全包裹
让委托的使用更具有安全性
事件是一种特殊的变量类型
事件的使用
声明语法
访问修饰符 event 委托类型 事件名
事件的使用:
1.事件是作为成员变量存在于类中
2.委托怎么用,事件就怎么用
事件相对于委托的区别:
1.不能在类外部 赋值
2.不能在类外部 调用
注意:
他只能作为成员存在于类和接口以及结构体中
class Test
{
//委托成员用来存储函数的
public Action myFun;
//事件成员变量,用来存储函数的
public event Action myEvent;

    public Test{//事件的使用和委托 一模一样。只有一些细微差别myFun=TextFun;myFun+=TextFun;myFun-=TextFun;myFun();myFun.Invoke();myFun=null;myEvent=TestFun;myEvent+=TestFun;myEvent-=TestFun;myEvent();myEvent.Invoke();myEvent=null;}public void DoEvent(){myEvent();myEvent.Invoke();}public void TestFun(){}
}class Program
{static void Main(string[] args){Console.WriteLine("事件");t.myFun=null;t.myFun=TestFun;//事件是不能在外部赋值的//t.myEvent=null;//t.myEvent=TestFun;//虽然不能直接赋值,但是可以加减去添加移除记录的函数t.myEvent+=TestFun;t.myEvent-=TextFun;//t.myEvent=t.myEvent- TextFun;  报错,不能使用赋值=,只能用复合运算符-=  +=//委托是可以在外部调用的t.Myfun();t.Myfun.Invoke();//事件不能在外部调用//t.myEvent();//只能在类的内部去封装调用t.DoEvent();Action a=TextFun;//事件是不能作为临时变量在函数中使用的//event Action ae=TextFun;}}为什么有事件1.防止外部随意置空委托2.防止外部随意调用委托3.事件相当于对委托进行了一次封装,让其更加安全总结:事件和委托的区别事件和委托的使用基本一模一样事件就是特殊的委托主要区别:1.事件不能在外部使用赋值=符号,只能用+ - ;委托到哪里都能用2.事件不能在外部执行;委托到哪里都能执行3.事件不能作为函数中的临时变量;委托可以

-----博主:mx

匿名函数
基本概念:
顾名思义就是没有名字的函数
匿名函数的主要作用就是配合委托和事件进行使用
脱离委托和事件是不会使用匿名函数的
基本语法:
delegate(参数列表)
{//函数列表}
何时使用?
1、函数中传递参数时
2、委托或者事件赋值时
使用
1.无参数无返回值
这样申明匿名函数只是在申明函数而已,还没有调用
真正调用他的时候,是这个委托容器啥时候调用,就什么时候调用这个匿名函数
Action a =delegate()
{
Console.WriteLine(“匿名函数逻辑”);
}

 2.有参数Action<int,string> b =delegate(int a,string b){Console.WriteLine(a);Console.WriteLine(b); }b(100,"123");3.有返回值Func<string> c = delegate(){return "123123";}Console.WriteLine(c);4. 一般情况会作为函数参数传递,或者作为函数返回值Test t=new Test() ;参数传递t. Dosomthing(100,delegate(){Console. WriteLine("随参数传入的匿名函数逻辑") ;}); 返回值Action ac2=t.GetFun();ac2();//一步到位直接调用返回的委托函数t.GetFun()();Class Test{public Action action;public void Dosomthing(int a ,Action fun){Console.WriteLine(a);fun();}public Action GetFun(){return delegate(){Console. WriteLine("返回匿名函数") ;};}}匿名函数的缺点:添加到委托或者事件容器后,不记录,无法单独移除Action ac3=delegate(){Console.WriteLine("匿名函数一");}ac3+=delegate(){Console.WriteLine("匿名函数二"); }ac3();因为匿名函数没有名字,所以没有办法指定移除某一个匿名函数此匿名函数非彼匿名函数,不能通过看逻辑是否一样,就证明是同一个ac3=null;总结:匿名函数 就是没有名字的函数固定写法:delegate(参数列表){}主要是在委托传递和存储时,为了方便可以直接使用匿名函数缺点是没有办法直接删除

Lambda表达式
什么是lambda表达式
可以将lambda表达式理解为匿名函数的简写
除了写法不同外,使用上基本与匿名函数一样
都是和委托或者事件配合使用

Lambda表达式语法匿名函数delegate(参数列表){};Lambda表达式(参数列表)=>{函数体};使用1.无参无返回Action a = ()=>{Console.WriteLine("无参无返回值的lambda表达式");}2.有参数Action<int> a2= (int value)=>{Console.WriteLine("有参数Lambda表达式{0}",value);}3.甚至参数类型都可以省略,参数类型和委托或者事件容器一致Action<int> a3=(value)=>{Console.WriteLine("有参数Lambda表达式{0}",value);}4.有返回值Func<string ,int> a4=(value)=>{Console.WriteLine("有参数Lambda表达式{0}",value);return 1;}闭包:内层函数可以引用包含在它外层的函数的变量即使外层函数的执行已经终止注意:该变量提供的值并非变量创建时的值,而是父函数范围内的最终值示例:class Test{public event Action action;public Test(){int value=10;//这里形成了闭包//因为当构造函数执行完毕时,其中申明的临时变量value的声明周期被改变了action =()=>{Console.WriteLine(value);}for(int i=0;i<10;i++){action +=()=>{Console.WriteLine(i);}}}public void DoEvent(){action =null;}}总结: 匿名函数的特殊写法就是lambda表达式固定写法就是  (参数列表)=>{}参数列表可以直接省略参数类型主要在委托传递和储存时为了方便可以直接使用匿名函数或者lambad表达式缺点:无法指定移除

List排序
List自带的排序方法
List list=new List();
list.Sort();
自定义类的排序
class Item:IComparable
{
public int money;
public Item(int value)
{
money=value;
}
public int CompareTo(Item other)
{
//返回值的含义:小于0就放在传入对象的前面
// 等于0就保持当前位置不变
// 大于0就保持对象的后面
//可以简单理解传入对象的位置就是0,如果你的返回为负数,就放在它的左边,也就前面
//如果返回正数,就放在它的右边,也就是后面
if(this.money>other.money)
{
return 1;
}
else
{
return -1;
}
return 0;
}s
}

    List<Item> itemlist=new List<Item>();itemlist.Add(new Item(45));itemlist.Add(new Item(4));itemlist.Add(new Item(5));itemlist.Add(new Item(15));itemlist.Add(new Item(55));itemlist.Add(new Item(65));itemlist.Add(new Item(47));itemlist.Add(new Item(40));itemlist.Sort();
通过委托函数进行排序List<Item> Shopitemlist=new List<Item>();Shopitemlist.Add(new Item(45));Shopitemlist.Add(new Item(4));Shopitemlist.Add(new Item(5));Shopitemlist.Add(new Item(15));Shopitemlist.Add(new Item(55));Shopitemlist.Add(new Item(65));Shopitemlist.Add(new Item(47));Shopitemlist.Add(new Item(40));Shopitemlist.Sort(SortShopItem);Shopitemlist.Sort(delegate (Item a,Item b){if(a.money>b.money){return 1;}else{return -1;}});Shopitemlist.Sort((Item a,Item b)=>{if(a.money>b.money){return 1;}else{return -1;}});static int SortShopItem(Item a,Item b){//传入的两个对象,为列表中的两个对象//进行两两比较,用左边的和右边的条件 比较//返回值规则和之前一样,0做标准,负数在前  正数在后if(a.money>b.money){return 1;}else{return -1;}}总结系统自带的变量(int double float...) 一般都可以直接Sort自定义了Sort有两种排序方法1.继承接口IComparable2.在Sort中传入委托函数

协变逆变
什么是协变逆变
协变和逆变是用来修饰泛型的
协变:out
逆变:in
用在泛型中修饰泛型字母的
只有泛型接口和泛型委托能使用

作用:1.返回值和参数用out修饰的泛型只能作为返回值delegate T TestOut<out T>();用in修饰的泛型只能作为参数delegate void TestIn(in T)(T t);2.结合里氏替换原则理解class Father{}class Son:Father{}class Program{static void Main(string[] args){Console.WriteLine("协变逆变");//协变 父类总是能被子类替换TestOut<Son> os= ()=> {return new Son();}TestOut<Father> of=os;Father f= of();//实际上 返回的是os里面装的函数,返回的是Son//逆变 父类总是能被子类替换TestIn<Father> iF=(value)=>{};TestIn<Son> iS=iF;iS(new Son());//实际上调用的是iF}}总结协变:out逆变: in用来修饰泛型替代符的,只能修饰接口和委托中的泛型作用两点:1.out修饰的泛型类型,只能作为返回值类型,in修饰的泛型类型只能作为参数类型2.遵循里氏替换原则,用out和in修饰的泛型委托,可以相互装载(有父子关系的泛型)        //口诀:协变 父类泛型委托装子类泛型委托, 逆变 子类泛型委托装父类泛型委托

多线程
了解线程前先了解进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动
是系统进行资源分配和调度的基本单位,是操作系统结构的基础
进程之间可以相互独立运行,互不干扰
进程之间可以相互访问、操作

什么是线程操作系统能够进行运算调度的最小单位他被包含在进程之中,是进程中的实际运作单位一条线程指的是进程中一个单一的顺序的控制流,一个进程中可以并发多个线程我们写的程序都在主线程中什么是多线程我们可以通过代码开启新的线程语法相关线程类 Thread需要引用命名空间 using System.Threading;1.声明一个新的线程注意线程执行的代码需要封装到一个函数中static bool IsRuning=true;static object obj =new object();Thread t= new Thread(NewThreadLogic);static void NewThreadLogic(){if(IsRuning)//新开线程,执行的代码逻辑,在该函数语句块中Console.WriteLine("新开线程运行");}2.启动线程t.Start();3.设置为后台线程当前台线程都结束了的时候,整个程序也结束了,即使后台线程正在运行也不会妨碍后台线程不会防止应用程序的进程终止掉如果不设置为后台线程,可能导致进程无法正常关闭t.IsBackground=true;4.关闭释放一个线程如果开启的线程中不是死循环,是能够结束的逻辑,那么不用刻意的去关闭它如果是死循环,想要中止这个线程有两种方式(1).死循环中的bool标识t=null;Console.ReadKey();IsRuning=false;Console.ReadKey();(2).通过线程提供的方法(注意在.Net core版本中无法终止,会报错)//终止线程t.Abort();5.线程休眠//让线程休眠多少毫秒  1s=1000毫秒//在哪个函数中执行就休眠哪个线程多少毫秒Thread.Sleep(1000);线程之间共享数据多个线程使用的内存是共享的们都属于该应用程序(进程)所以要注意当多线程同时操作同一片内存区域时可能会出现问题可以通过加锁的形式避免问题lock当我们在多个线程当中想要访问同样的东西的时候,进行逻辑处理时为了避免不必要的逻辑顺序执行的差错lock(引用类型){}
多线程对于我们的一样可以用多线程专门处理一些复杂耗时的逻辑比如寻路、网络通信等

反射
什么是程序集
程序集是经由编译器编译得到的,供进一步编译执行的那个中间产物
在Windows系统中他的一般表现为.dll(库文件)或者是.exe(可执行文件)的格式

元数据元数据就是用来描述数据的数据这个概念不仅仅是用于程序上,在别的领域也有元数据反射程序在运行是,可以查看其他程序集或者自身的元数据一个运行的程序查看本身或者其他程序的元数据的行为叫反射反射的作用因为反射可以在程序编译后获得信息,所以它提高了程序的拓展性和灵活性1.程序运行时得到所有元数据,包括元数据特性2.程序运行时,实例化对像,操作对象3.程序运行时创建新对象,用这些多像执行任务class Test
{private int i=1;public int j=0;public string str="123";public Test(){}public Test(int i){this.i=i;}public Test(int i,string str):this(i){this.str=str;}public void Speak(){Console.WriteLine(i);}}语法相关TypeType(类的信息类)他是反射功能的基础他是访问元数据的主要方式使用Type的成员获取有关类型声明的信息有关类型的成员(如构造函数、方法、字段、属性和类的属性)获取Type1.万物之父object中GetType()可以获取对象的Type2.通过typeof关键字传入类名也可以获取到对象的Type3.通过类的名字也可以获取到类型注意:类名必须包含命名空间,不然找不到得到类的程序集信息可以通过Type可以得到类型所在程序集信息获取类中的所有公共成员首先得到Type然后得到所有的公共成员需要引用命名空间 using System.Reflection;获取类的公共构造函数并调用1.获取所有的构造函数2.获取其中一个构造函数并调用得构造函数传入 Type数组 数组中的内容按顺序是参数类型执行构造函数传入 object数组 表示按顺序传入的参数2-1 得到无参构造2-2 得到有参构造获取类的公共成员变量1.得到所有的成员变量2.得到指定名称的公共成员变量3.通过反射获取和设置对象的值3-1 通过反射获取对象的某个变量的值3-2 通过反射 设置指定对象的某个变量的值获取类的公共成员方法通过Type类中的GetMethod方法得到类的方法1Methinfo是方法的反射信息1.如果存在方法重载,用Type数组表示参数类型2.调用该方法注意如果是静态方法,Invoke中的第一个参数传入null即可其他得枚举:GetEnumNameGetEnumNames得事件:GetEventGetEvents得接口:GetInterfaceGetInterfaces得属性:GetPropertyGetInterfaces等等Activator用于快速实例化对象的类用于将Type对象快速实例化为对象先得到Type然后快速实例化一个对象1.无参构造2.有参数构造Assembly程序集类主要用来加载其它程序集,加载后才能用Type来使用其他程序集中的信息如果想要使用不是自己程序集中的内容,需要先加载程序集比如dll文件三种加载程序集的函数一般用来加载同一文件下的其他程序集Assembly assembly2=Assembly.Load("程序集名称");一般用来加载不同文件夹下的其他程序集Assembly assembly=Assembly.LoadFrom("包含程序集清单的文件的名称或路径");Assembly assembly3=Assembly.LoadFile("要加载的文件的完全限定路径");1.先加载一个指定的程序集2.在加载程序集中的一个类对象,之后才能使用反射class Program
{static void Main(string[] args){Console.WriteLine("反射");int a=42;//获取TypeType type=a.GetType();Console.WriteLine(type);Type type2=typeof(int);Console.WriteLine(type2);Type type3=Type.GetType("System.Int32");Console.WriteLine(type3);//得到类的程序集信息Console.WriteLine(type.Assembly);Console.WriteLine(type2.Assembly);Console.WriteLine(type3.Assembly);//获取类中的所有公共成员Type t=typeof(Test);MemberInfo[] infos=t.GetMember();for(int i=0;i<infos.Length;i++){Console.WriteLine(infos[i]);}//获取类的公共构造函数并调用ConstrutorInfo[] ctors=t.GetConstructors();for(int i=0;i<ctors.Length;i++){Console.WriteLine(ctors[i]);}//执行无参构造 无参构造 没有参数 传nullConstrutorInfo info=t.GetConstructors(new Type[0]);Test obj =info.Invoke(null) as Test;Console.WriteLine(obj.j);//执行有参构造ConstrutorInfo info2=t.GetConstructors(new Type[]{typeof(int)});obj=info.Invoke(new object[]{2}) as Test;Console.WriteLine(obj.str);ConstrutorInfo info2=t.GetConstructors(new Type[]{typeof(int),typeof(string)});obj=info.Invoke(new object[]{2,"2333"}) as Test;Console.WriteLine(obj.str);//得到所有的成员变量FieldInfo[] fieldInfos=t.GetField();for(int i=0;i<fieldInfos.Length;i++){Console.WriteLine(fieldInfos[i]);}//得到指定名称的公共成员变量FieldInfo infoJ=t.GetField("j");Console.WriteLine(info3);//通过反射获取和设置对象的值Test test=new Test();test.j=99;test.str="2222";Console.WriteLine(infoJ.GetValue(test));infoJ.SetValue(test,100);Console.WriteLine(infoJ.GetValue(test));//获取类的公共成员方法Type strType=typeof(string);MethodInfo[] methods=strType.GetMethods();for(int i=0;i<methods.Length;i++){Console.WriteLine(methods[i]);}MethodInfo subStr=strType.GetMethod("Substring",new Type[]{typeof(int),typeof(int)});string str="Hello World!";object result=subStr.Invoke(str,new object[]{7,5});Console.WriteLine(result);//ActivatorType testType= typeof(Test);//无参构造Test testObj activator.CreateInstance(testType) as Test;Console.WriteLine(testObj.str);//有参构造testObj=Activator.CreateInstance(testType,99)as Test;Console.WriteLine(testObj.j);testObj=Activator.CreateInstance(testType,99,"1232123")as Test;Console.WriteLine(testObj.j);//Assembly//1.先加载一个指定的程序集Assembly assembly =Assembly.LoadFrom("路径");Type[] types=assembly.GetTypes();for(int i=0;i<types.Length;i++){Console.WriteLine(types[i]);}//2.在加载程序集中的一个类对象,之后才能使用反射Type icon=assembly.GetType("类名称");MemberInfo[] menbers=icon.GetMembers();for(int i=0;i<menbers.Length;i++){Console.WriteLine(menbers[i]);}//通过反射实例化一个对象//首先得到枚举Type来得到可以传入的参数Type moveDir=assembly.GetType("类名称");FieldInfo right=moveDir.GetField("Right");//直接实例化对象object iconObj=Activator.CreateInstance(icon.10,5,right.GetValue(null));//得到对象中的方法,通过反射MethodInfo move=icon.GetMethod("Move");MethodInfo draw=icon.GetMethod("Draw");MethodInfo clear=icon.GetMethod("Clear");Console.Clear();while(true){Thread.Sleep(1000);clear.Invoke(iconObj,null);move.Invoke(iconObj,null);draw.Invoke(iconObj,null);}}}总结:反射在程序运行时,通过反射可以得到其他程序集或者自己程序集代码的各种信息,如类、函数、变量、对象等等,实例化他们、执行他们、操作他们关键类TypeAssemblyActivator为什么要学反射unity引擎的基本工作机制就是建立在反射的基础上

-----博主:mx
特性
什么是特性:
特性是一种允许我们向程序的程序集添加元数据的语言结构
他是用于保存程序结构信息的某种特殊类型的类

    特性提供功能强大的方法以将声明信息与c#代码(类型、方法、属性等)相关联特性与程序实体关联后,即可再运行时使用反射查询特性信息特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集中他可以放置几乎所有的声明中(类、变量、函数等等声明)自定义特性继承特性基类:Attributeclass MyCustomAttribute:Attribute{public string info;public MyCustomAttribute(string info){this.info=info;}}
特性的使用基本语法:[特性名(参数列表)]本质上 就是在调用特性类的构造函数写在哪里?类、函数、变量上一行,表示他们具有该特性信息限制自定义特性的使用范围通过为特性类加特性限制其使用范围[AttributeUsage(AttributeTargets.Class)|AttributeTargets.Struct|AttributeTargets.Field,AllowMultiple=true,Inherited=true)]参数一: AttributeTargets ---特性能够用在哪些地方参数二: AllowMultiple---是否允许多个特性实例用在同一个目标上参数三: Inherited---特性是否能被派生类和重写成员继承系统自带特性---过时特性过时特性Obsolete用于提示用户使用的方法等成员已经过时了,建议使用新方法一般加在函数前的特性参数一:调用过时方法时,提示的内容参数二:true-使用该方法时会报错,false-使用该方法时直接警告[Obsolete("OldSpeak方法已经过时了,请使用Speak方法"),true]系统自带特性---调用者信息特性哪个文件调用?CallerFilePath特性哪一行调用?CallerLineNumber特性哪个函数调用?CallerMemberName特性需要引用命名空间 using System.Runtime.ComilerServices;一般作为函数参数的特性[MyCustom("这个是我自己写的一个用于计算的类")]class MyClass{[MyCustom("这个一个成员参数")]public int value;[MyCustom("这个一个用于计算加法的类")]public void TestFun([MyCustom("函数参数")] int a){}}系统自带特性---条件编译特性条件编译特性Conditional它会和预处理指令 #define配合使用需要引用命名空间 using System.Diagnostics主要可以用在一些调试代码上有时想执行有时不想执行的代码系统自带特性---外部Dll包函数特性DllImport用来标记非.Net(c#)的函数,表名该函数在一个外部的DLL中特性一般用来调用其他语言的Dll写好的方法需要引用命名空间 using System.Runtime.InteropServices[DllImport("Test.dll")]public static extern int Add(int a,int b);class Program{static void Main(string[] args){Console.WriteLine("特性");MyClass mc=new MyClass();Type t=mc.GetType();//t=typeof(MyClass);//t=Type.GetType("路径名称");//判断是否使用了某个特性//参数一:特性的类型;参数二:代表是否搜索继承链(属性和事件忽略此参数)if(t.IsDefined(typeof(MyCustomAttribute),false)){Console.WriteLine("该类型应用了MyCustomAttribute的特性");}//获取Type元数据中的所有特性object[] array=t.GetCustonAttributes(true);for(int i=0;i<array.Length;i++){if(array[i] is MyCustomAttribute){Console.WriteLine(array[i] as MyCustomAttribute);(array[i] as MyCustomAttribute).TestFun();}}}}总结:  特性是用于为元数据再添加更多的额外信息(变量、方法等等)我们可以通过反射获取这些额外的数据来进行一些特殊处理自定义特性--继承Attribute类系统自带的特性为什么要学特性unity引擎中很多地方用到了特性来进行一些特殊处理

迭代器
迭代器是什么
迭代器(iterator)有时又称光标(cursor)
是程序设计的软件设计模式
迭代器模式提供了一个顺序访问一个聚合对象中的各个元素
而又不保留其内部的表示

    从表现效果上看是可以在容器对象(例如链表或者数组)上遍历访问的接口设计人员无需关心容器对象的内存分配的实现细节可以用foreach遍历的类,都是实现了迭代器的标准迭代器的实现方法关键接口:IEnumerator,IEnumerable命名空间:using System.Collections;可以通过同时继承IEnumerable和IEnumerator实现其中的方法class CustomList:IEnumerable,IEnumerator{private int[] list;//从-1开始的光标用于表示数据得到了哪个位置private int position=-1;public CustomList(){list=new int[]{1,2,3,4,5,6,7,8};}public IEnumerator GetEnumerator(){Reset();return this;}public object Current{get{return list[position];}};public bool MoveNext(){++position;//是否移除,溢出就不合法return position<list.Length;}//重置光标位置,一般写在获取 IEnumerator这个函数中public void Reset(){position=-1;}}用yield return 语法糖实现迭代器yield return 是c#提供给我们的语法糖所谓语法糖也称为糖衣语法主要作用就是将复杂逻辑简单化,可以增加程序的可读性从而减少程序代码出错的机会关键接口: IEnumerator命名空间: using System.Collections;让想要通过foreach遍历的自定义类实现接口中的方法 GetEnumerator 即可class CustomList2:IEnumerable,IEnumerator{private int[] list;public CustomList2(){list=new int[]{1,2,3,4,5,6,7,8};}public IEnumerator GetEnumerator(){for(int i=0;i<list.Length;i++){//协程yield return list[i];}}}用yield return 语法糖为泛型类实现迭代器class CustomList3<T>:IEnumerable{private T[] list;public CustomList3(params T[] array ){this.list=list;}public IEnumerator GetEnumerator(){for(int i=0;i<list.Length;i++){//协程yield return array[i];}}}

-----博主:mx
class Program
{
static void Main(string[] args)
{
Console.WriteLine(“迭代器”);
CustomList list =new CustomList();

        //foreach本质//1.先获取in后面这个对象的 IEnumerator//会调用其中的GetEnumerator方法来获取//2.执行得到这个IEnumerator对象中的MoveNext方法//3.只要MoveNext方法的返回值时true,就会得到Current,然后赋值给itemforeach(int item in list){Console.WriteLine(item);}CustomList2 list2 =new CustomList2();foreach(int item in list2){Console.WriteLine(item);}CustomList3<string> list2 =new CustomList3<string>("123","123312","456");foreach(string item in list2){Console.WriteLine(item);}}
}总结:迭代器就是可以让我们在外部直接通过foreach遍历对象中元素而不需要了解其结构主要的两种方式1.传统方式 继承两个接口,实现里面的方法2.用语法糖yield return 去返回内容,只需要继承一个接口

特殊语法
var隐式类型
var是一种特殊的变量类型
它可以用来表示任意类型的变量
注意:
1.var不能作为类的成员,只能用于临时变量声明时
也就是一般写在函数语句块中
2.var必须初始化
var i =5;
var s=“123”;
var array=new int[]{1,2,3,4,5};
var list =new List();

设置对象的初始值声明对象时可以通过直接写大括号的形式初始化公共成员变量和属性Person p=new Person(){sex=true,age=15,name="好耶"};设置集合初始值声明集合对象时也可以通过大括号,直接初始化内部属性int[] array2=new int[]{1,2,3,4,5,6};List<int> listInt=new list<int>(){1,2,3,4,5,6};匿名类型var变量可以声明为自定义的匿名类型,只能有成员变量,不能有函数var v=new{age=10,money=11,name="小明"};可空类型1.值类型是不能赋值为空的2.声明时再值类型后面加? 可以赋值为空int? c=null;3.判断是否为空if(c.HasValue){Console.WriteLine(c);Console.WriteLine(c.Value);}4.安全获取可空类型值4.1 如果为空,默认返回值类型的默认值Console.WriteLine(value.GetValueOrDefault());4.2 也可以指定一个默认值Console.WriteLine(value.GetValueOrDefault(100));//相当于是一种语法糖能够帮助我们自动判断o是否为空//如果是null就不会执行tostring也不会报错object o=null;Console.WriteLine(o?.ToString());int[] arrayInt=null;Console.WriteLine(arrayInt?[0]);Action action=null;action?.Invoke();空合并操作符空合并操作符 ??左边值 ?? 右边值如果左边值为null 就返回右边值 否则返回左边值只要是可以为null的类型就能用int? intV=null;//int intI= intV==null? 100 : intV.value;int intI=intV ?? 100;内插字符串关键符号 $用$来构造字符串,让字符串可以拼接变量string name="好耶";int age=18;Console.WriteLine($"好好学习,{name},年龄:{age}");单句逻辑的简略写法循环,判断if只有一句时,只会执行接着的第一句if(true)Console.WriteLine("好耶");while(true)Console.WriteLine("好耶");for(int j=0;j<10;j++)Console.WriteLine("好耶");函数只有一句时有返回值是直接返回,无返回值则执行操作public int Add(int x,int y) => x+y;public void Speak(string str) => Console.WriteLine(str);

值和引用类型
值类型:
无符号:byte,ushort,uint,ulong
有符号:sbyte,short,int,long
浮点数:float,double,decimal
特殊:char ,bool
枚举:enum
结构体:struct
引用类型:
string
数组
class
interface
委托

值类型和引用类型的本质区别值类型的具体内容存在栈上引用类型的具体内容存在堆上问题一:如何判断值类型和引用类型F12进入到类型内部去查看是class就是引用类型是struct就是值类型问题二:语句块命名空间												

Unity相关--C#入门到进阶相关推荐

  1. Unity新手入门与进阶学习书籍与教程推荐

    读研的时候喜欢做游戏,最开始在诺基亚N9手机上开发过几款产品,有APP也有游戏.用的是Qt Quick,最先在N9上发布,之后又了解到黑莓的BB10系统,也可以用Qt Quick开发,所以就把几个产品 ...

  2. ab753变频器参数怎么拷贝到面板_【干货】一文让你从入门小白进阶为变频器高手...

    点击蓝字 关注我们 为确保 SINAMICS G120 的操作及监控便捷高效,提供了三种不同的操作面板: 1.基本操作面板(BOP-2). 2.智能操作面板(IOP-2) 3.智能连接模块(G120 ...

  3. 程序员编程如何入门、进阶?

    作者 | 码农唐磊 来源 | 程序猿石头(ID:tangleithu) 背景 在之前的这篇文章中,我谈了谈读本科的时候都学了哪些计算机专业课和推荐了一些经典的技术书籍,然后推文封面中的这张图引起了不少 ...

  4. python数据结构推荐书-「算法与数据结构」从入门到进阶吐血整理推荐书单

    推荐一下「算法与数据结构」从入门到进阶的书单. 一.入门系列 这些书籍通过图片.打比方等通俗易懂的方法来讲述,让你能达到懂一些基础算法,线性表,堆栈,队列,树,图,DP算法,背包问题等,不要求会实现, ...

  5. 摊牌了,我靠它们成功实现了AI零基础入门到进阶!

    随着科技的高速发展,人工智能正成为引领科技创新和产业发展的核心力量,人工智能产品与服务正在持续地渗透到人们的日常工作.生活.学习和社交等领域,也推动了各区域.各类型的科技企业和传统产业企业纷纷向人工智 ...

  6. python 三维绘图库_Python第三方库matplotlib(2D绘图库)入门与进阶

    Matplotlib 一 简介: Matplotlib是一个Python 2D绘图库,它可以在各种平台上以各种硬拷贝格式和交互式环境生成出具有出版品质的图形. Matplotlib可用于Python脚 ...

  7. java入门学习_Java入门学习进阶知识点

    Java入门学习进阶知识点 入门阶段,主要是培养Java语言的编程思想.了解Java语言的语法,书写规范等,掌握Eclipse.MyEclipse等开发工具,编写Java代码的能力.学完这个阶段你应该 ...

  8. [资源]推荐一些Python书籍和教程,入门和进阶的都有!

    前几天后台有读者留言说希望推荐一些入门的书籍,所以这几天都在整理一些我入门时候学习过的书籍教程,或者是口碑还不错的书籍! 入门和进阶书籍教程 入门和进阶方面的书籍教程,这里推荐两本书和一个教程. 1. ...

  9. 100例Python代码带你从入门到进阶!

    以下所有代码全都至少运行一遍,确保可复现.易于理解.逐步完成入门到进阶的学习. 此教程经过我 反复打磨多遍 ,经常为此熬夜,真心不易,文章比较长,看完有用,帮我点个在看或分享支持. 教程包括 62 个 ...

最新文章

  1. 常用Linux命令(续)
  2. Android Design Library之三: NavigationView
  3. java学习笔记12--异常处理
  4. 测试用html文件是否存在,ASP如何检测某文件夹是否存在,不存在则自动创建
  5. vCenter 6.0安装部署
  6. Shell 脚本中如何使用make命令
  7. 微课|玩转Python轻松过二级(3.2节):元组与生成器推导式
  8. 本地mysql数据库初始密码_忘记本地MySQL数据库密码的解决方法
  9. Netflix 混沌工程手册 Part 3:实践方法
  10. 2018年上半年 系统分析师 论文 真题
  11. 查看python源码位置方法以及潜在误区
  12. 解决win 7拷贝共享文件很慢
  13. mmdetectionv2.0修改类别数与数据集图片后缀
  14. 通过whoscored网站对转会球员的评分来比较五大联赛水平高低
  15. 如何防止SP利用欠费进行套利
  16. React 安装 node-sass失败解决方案
  17. SAP PP生产计划体系
  18. RedisTemplate与jedis
  19. Xcode7与Xcode8及Xcode8.1之间兼容的那些事(持续更新)
  20. matlab巴克码发生器,2018年移动通信课程设计题目.doc

热门文章

  1. 图书商城APP系统(基于uni-app框架)毕设毕业设计毕业论文开题报告参考(上)app功能界面
  2. 如何在idea中使用翻译
  3. AutoAugment: Learning Augmentation Policies from Data(一种自动数据增强技术)
  4. 基于Spring Boot的网咖管理系统
  5. 如何用最短的时间学会数据分析?
  6. NODE.JS语言的短信接口好对接吗
  7. 微信小程序实现(置顶)和(置底)功能
  8. 卷积神经网络是一类包含卷积计算且具有深度结构的前馈神经网络
  9. 黑马程序员--分布式搜索ElasticSearch学习笔记
  10. 计算机氧气游戏,在Klei的新游戏《缺氧》里,氧气绝不仅仅是种资源那么简单...