1、委托——delegate\Action
1.1 delegate
委托可以理解为函数指针。
委托delegate关键词,Delegate和delegate都可以,这个类似于string和String,c#程序编写一般还是用delegate小写的。委托定义的变量和类定义的变量一样,也是一种类型的对象。
public delegate void Game();//定义一个委托,这是一个类型,注意区别类型和对象的区别,对象是类型的具体化可以这样理解,Game现在就是一个类型,可以用Game定义Game类型的对象,这个类型是无返回值无参数的委托类型
//声明一种委托对象的方式
//方式01
public Game game_01;//定义一个委托的实例对象,和定义变量一样,直接定义,这时候game_01值为null
//方式02
Game game_01=new Game(“方法名称”);//和类的声明不同,委托声明的时候括号内必须有值,也就是方法名称,错误提示为“Game不包含0个参数的构造函数”,类括号内无参数是因为类的构造函数没有参数
public void Play(Game game)
{
//委托的执行方式有
//方式01,直接加上括号,就执行了所指向的方法
game();
//方式02,
game.Invoke();//这种方式也有人在用,一般都是用上一种方法,这一种见到了知道是什么意思就行
}
//下面定义了几个游戏
public void WangZheRongYao()
{
Console.WriteLine("王者荣耀");
}
public void HePingJingYing()
{
Console.WriteLine("和平精英");
}
static void Main(string[] args)
{
Game game;
game=WangZheRongYao;
Play(game);//Play需要传入的是委托类型
Console.ReadKey();
#region
Game game_01=new Game(WangZheRongYao);
Play(game_01);
Console.ReadKey();
#endregion
}
可以这样理解:delegate这个关键词的使用和class关键词的使用类似。首先是这两个关键词在写法上是小写,其次在创建上也是非常相近,还有就是委托和类的等级一样,都是定义在命名空间,委托不是包含在类中,当然委托也可以定义在类中,委托类型是一种函数指针,就是等于函数名称,这个委托类型的变量保存的就是这个函数在内存中的地址。
另外在声明委托对象和类对象的时候有点不同,用new关键字后面的括号里面委托需要传入参数,类因为有无参的构造函数所以不要传入参数。
- 委托是引用类型,在没有被赋值时候为null;
- 因为委托存放的为函数地址,所以定义委托时候会有“返回值类型”和“括号”以及“括号内的形参”;
- 理解声明和定义,在创建类的时候总是说“定义一个类”,定义一个新的委托类型的时候会说“声明委托”
- 委托声明了以后就定了可以由这个委托引用的方法,这个委托就只能引用和他有相同标签的方法,也就是说和他有相同返回值和传入参数的方法;
- 一旦声明了委托类型,委托对象要用new关键字来创建,且与一个方法有关;
- 一旦声明了一个或者说定义了一个类对象,类对象就要用new关键字来创建,并调用构造函数,
- 其实类和委托一样
- 需要注意的是:委托对象创建的时候new关键字后面括号里面为函数名称,不带参数;
例如:
//我们在定义一种新“对象”类型的时候
//定义一个学生Student类
public class Student
{
}
//实例化一个student对象
Student student=new Student();//无参数,调用的是构造函数
//我们在定义一个新的委托类型的时候
//定义一个新“委托”类型的时候
//定义一个Delegate委托
public delegate void DD();
DD dd=new DD(function);//有参数,参数为function,必须有参数,因为委托没有构造方法
dd();//这就算执行了function函数了,就是在委托变量的后面加上括号,也可以dd.Invoke()
1.2 Action
class Interpreter
{
public void SayHi(Action language)
{
language.Invoke();
}
public void Chinese()
{
Console.WriteLine("你好");
}
}
static void Main(string[] args)
{
Interpreter interpreter = new Interpreter();
Action language = interpreter.Chinese;
interpreter.SayHi(language);
Console.ReadKey();
}
public delegate void Language();//定义一个委托类型
class Interpreter
{
public void SayHi(Language language)
{
//language();
language.Invoke();
}
public void Chinese()
{
Console.WriteLine("你好");
}
}
static void Main(string[] args)
{
Language language;
Interpreter interpreter = new Interpreter();
//下面的这个动作就可以理解为插卡动作
language = interpreter.Chinese;//注意这里不能加括号,只是把函数名的地址给到委托
if(language==null)
{
Console.WriteLine("没有检测的插卡!");
}
interpreter.SayHi(language);
Console.ReadKey();
}
从上面两段代码可以看出来,Action就是委托,只是对delegate的进一步封装,用action就不用先定义委托了。
2、线程——Thread/Task
线程=任务
Task是Thread的一个包装类,使用方法基本上和Thread一样
ParameterizedThreadStart ParStart = new ParameterizedThreadStart(ThreadMethod);
Thread myThread = new Thread(ParStart);
object o = "hello";
myThread.Start(o);
//ThreadMethod如下:
public void ThreadMethod(object ParObject)
{
//程序代码
}
带参数的方法需要这样开多线程
Thread线程
Task任务,对线程的封装
Task.Run();
delegate委托
event delegate
Action对委托的封装
event Action()
时间委托
委托的广播和订阅,实现数据传递
this.Invoke(new Action(()=>{});委托给一个匿名函数
线程的取消
CancellationTokenSource
2.1 同步
同步的sync,界面会卡顿,
2.2 多线程
开启多个线程,多个线程会同时执行
2.3 异步多线程
异步多线程是像同步一样,执行上有一定的顺序,异步多线程有关键字await、async关键字
3、事件——event
关于委托事件event和多线程Thread,这两个会一起出现,这是一种设计模式的问题,委托事件的广播和订阅的概念,
如果一个进程中有多个线程,线程之间的数据是不能被调用和访问的,一个线程想要访问其他线程的数据就要用的委托,用到委托就有了委托事件,就有了委托事件的广播和订阅的概念。
委托事件的定义和委托一样,就是在关键词Action前面加上event关键字
委托事件的订阅是“+=”,vs可以自动生成订阅事件的函数
class TaoBao//定义了一个淘宝类型,
{
List<string> list =new List<string>
{
"淘宝产品-01",
"淘宝产品-02",
"淘宝产品-03",
"淘宝产品-04",
"淘宝产品-05",
"淘宝产品-06",
"淘宝产品-07",
"淘宝产品-08",
"淘宝产品-09",
"淘宝产品-10",
}
public event Action<string> SetDatas;//这里定义了一个委托事件,函数名为SetDatas,带参数,参数为string类型
//其他方法
public void CollectDatas()
{
foreach(string item in list)//list是一个列表数据,这里是取出每个元素
{
SetDatas(item);//把采集到的数据通过一个委托方法发送到别的线程,这里是主窗体的UI线程,
//调用这个方法就是把数据广播出去,谁订阅就能得到这个数据,进而处理这个数据
Thread.Sleep(1000);
}
}
//这里写订阅
private void btnStart_Click(object sender,EventArgs e)
{
//实例化一个淘宝类
TaoBao taobao =new TaoBao();
taobao.SetDatas+=Taobao_SetDatas;//这里就是订阅事件,这里vs可以自动给你定义一个委托方法,方法的名称
//方法的名称和定义都自动可以生成,这里只是订阅了事件,但是现在这个实例化对象还是空值null,里面并没有数据
Thread t1=new Thread(taobao.CollectDatas);//创建一个线程,传入的参数是一个委托类型,也就是一个函数名称
t1.Start();//开启线程任务
}
private void Taobao_SetDatas(string obj)
{
//上面的obj就是广播过来的字符串string格式的数据,现在通过订阅到这个广播,就能拿到这个数据
//拿到这个数据后就可以把它赋值给窗体上的控件,
this.lbDatas.Invoke(new Action(()=>{//关于句柄,窗体上的控件都有一个句柄id作为标识,这里就是找到这个控件所在的
//线程,让后把数据给到这个线程,然后显示的
//注意:其实这里执行的代码是窗体线程的,
this.lbDatas.Items.Add(obj);
}));
}
4、lamda表达式
运算符 “=>”意思是:go to
(参数)=>{函数体}
意思是参数传递到函数体内,可以这样的理解。