C#语言入门详解---委托(刘铁猛)

委托:函数指针的升级版,可以类比C语言中的函数指针进行理解

变量的本质就是以变量名所对应的内存地址为起点的一段内存,这段内存中存储的就是变量的数据,这段内存的大小由变量的数据类型决定。

函数代表算法,函数的本质是以函数名所对应的内存地址为起点的一段内存中,这段内存中存储的不是某个值,而是一组机器语言的指令,CPU就是按照这组指令一条一条执行完成这段函数中所包含的算法。

无论是数据还是算法都是保存在内存中的,变量是用来寻找数据的地址,函数是用来寻找算法的地址。

C#通过委托这种数据类型保留了与C/C++语言中函数指针对应的功能。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 委托_刘铁猛
{class Program{static void Main(string[] args){Caculator caculator = new Caculator();Action action = new Action(caculator.Report);Func<int, int, int> func1 = new Func<int, int, int>(caculator.Add);Func<int, int, int> func2 = new Func<int, int, int>(caculator.Sub);caculator.Report(); //直接调用action.Invoke();    //间接调用1action();           //间接调用2int a = 200;int b = 300;int c = 0;//直接调用c = caculator.Add(a, b);Console.WriteLine(c);c = caculator.Sub(a, b);Console.WriteLine(c);//间接调用1c = func1.Invoke(a, b);Console.WriteLine(c);c = func2.Invoke(a, b);Console.WriteLine(c);//间接调用2c = func1(a, b);Console.WriteLine(c);c = func2(a, b);Console.WriteLine(c);}}class Caculator{public void Report(){Console.WriteLine("I have 3 methods");}public int Add(int a, int b){int result = a + b;return result;}public int Sub(int a, int b){int result = a - b;return result;}}
}

自定义委托时一定要注意:

1)委托与封装的方法必须类型兼容,返回值和参数的数据类型和参数数目需一致

2)委托是一种类,因此将其声明在名称空间里面时其和其它类处于同一级。C#中允许嵌套类,即在一个类中可以嵌套另一个类,因此若将委托放到某一个类中,则委托就变成了该类中的嵌套类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 委托_刘铁猛
{public delegate double Calc(double x, double y);    //定义委托class Program{static void Main(string[] args){Calculator calculator = new Calculator();Calc calc1 = new Calc(calculator.Add);Calc calc2 = new Calc(calculator.Sub);Calc calc3 = new Calc(calculator.Mul);Calc calc4 = new Calc(calculator.Div);double a = 100;double b = 200;double c = 0;c = calc1.Invoke(a, b);//等价于c = calc1(a, b);Console.WriteLine(c);c = calc2.Invoke(a, b);Console.WriteLine(c);c = calc3.Invoke(a, b);Console.WriteLine(c);c = calc4.Invoke(a, b);Console.WriteLine(c);Console.WriteLine("-------------------------");Calc[] calcArray = new Calc[4];calcArray[0] = calculator.Add;calcArray[1] = calculator.Sub;calcArray[2] = calculator.Mul;calcArray[3] = calculator.Div;foreach (var item in calcArray){c = item.Invoke(a, b);//等价于c = item(a, b);Console.WriteLine(c);}}}class Calculator{public double Add(double x, double y){return x + y;}public double Sub(double x, double y){return x - y;}public double Mul(double x, double y){return x * y;}public double Div(double x, double y){return x / y;}}
}

模板方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 委托_刘铁猛
{public delegate double Calc(double x, double y);    //定义委托class Program{static void Main(string[] args){ProductFactory productFactory = new ProductFactory();WrapFactory wrapFactory = new WrapFactory();Func<Product> func1 = new Func<Product>(productFactory.MakePizza);Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);Box box1 = wrapFactory.WrapProduct(func1);Box box2 = wrapFactory.WrapProduct(func2);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);}}class Product{public string Name { get; set; }}class Box{public Product Product { get; set; }}class WrapFactory{/// <summary>/// 模板方法,委托的调用getProduct是可以修改的地方,传入不同的getProduct可以实现/// 不同的产出产品,不同的产品不用再修改WrapProduct中的方法/// </summary>/// <param name="getProduct"></param>/// <returns></returns>public Box WrapProduct(Func<Product> getProduct){Box box = new Box();                      //准备一个BoxProduct product = getProduct.Invoke();    //获取一个产品box.Product = product;                    //把产品装到Box里面return box;                               //返回Box}}class ProductFactory{public Product MakePizza(){Product product = new Product();product.Name = "Pizza";return product;}public Product MakeToyCar(){Product product = new Product();product.Name = "Toy Car";return product;}}
}

参照如上代码,体会使用模板方法的好处是:Product类、Box类、WrapFactory类都不用修改,只需要扩展ProductFactory类中的产品就可以生产不同的产品。不管是生产哪种产品的方法,只要将该方法封装到委托类型的对象里传给模板方法,调用模板方法时就可以将产品包装成箱子再交还回来,这样可以最大限度的实现代码的重复使用。代码的复用不但可以提高工作效率,还可以减少程序Bug的引入,良好的复用结构是所有优秀软件所追求的共同目标之一。

回调方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 委托_刘铁猛
{public delegate double Calc(double x, double y);    //定义委托class Program{static void Main(string[] args){ProductFactory productFactory = new ProductFactory();WrapFactory wrapFactory = new WrapFactory();Func<Product> func1 = new Func<Product>(productFactory.MakePizza);Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);Logger logger = new Logger();Action<Product> log = new Action<Product>(logger.Log);Box box1 = wrapFactory.WrapProduct(func1, log);Box box2 = wrapFactory.WrapProduct(func2, log);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);}}class Logger{public void Log(Product product){Console.WriteLine("Product {0} created at {1}. Price is {2}",product.Name, DateTime.UtcNow, product.Price);}}class Product{public string Name { get; set; }public double Price { get; set; }}class Box{public Product Product { get; set; }}class WrapFactory{/// <summary>/// 模板方法,委托的调用getProduct是可以修改的地方,传入不同的getProduct可以实现/// 不同的产出产品,不同的产品不用再修改WrapProduct中的方法/// </summary>/// <param name="getProduct"></param>/// <returns></returns>public Box WrapProduct(Func<Product> getProduct, Action<Product> logCallback){Box box = new Box();                      //准备一个BoxProduct product = getProduct.Invoke();    //获取一个产品if (product.Price >= 50)    //产品价格大于等于50则打印log信息{logCallback(product);}box.Product = product;                    //把产品装到Box里面return box;                               //返回Box}}class ProductFactory{public Product MakePizza(){Product product = new Product();product.Name = "Pizza";product.Price = 12;return product;}public Product MakeToyCar(){Product product = new Product();product.Name = "Toy Car";product.Price = 100;return product;}}
}

回调关系是对于某个方法可以调用或者不调用,用的着的时候调用它,用不着得时候不调用它。回调方法还给了我们一个机会,可以动态的选择后续将被调用的方法(有多个备选方法)。当以回调方法的形式使用委托时,需将委托类型的参数传进主调方法里面,被传入抓主调方法中的委托的参数它内部会封装一个被回调的方法。主调函数会根据自己的逻辑来决定是否要调用回调方法。一般情况下,主调方法会在主要逻辑执行完之后,决定是否需要调用回调方法。

无论是模板方法还是回调方法,其本质都是用委托类型的参数封装一个外部的方法,然后将这个委托传入方法的内部来进行间接调用。委托的功能非常强大,但使用不当会造成严重的后果。

单播委托:一个委托封装一个方法

多播委托:使用一个委托封装多个方法,在调用时执行的顺序按照封装的顺序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;namespace 委托_刘铁猛
{class Program{static void Main(string[] args){Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.White };Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Blue };Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Yellow };Action action1 = new Action(stu1.DoHomework);Action action2 = new Action(stu2.DoHomework);Action action3 = new Action(stu3.DoHomework);//单播委托action1.Invoke();action2.Invoke();action3.Invoke();//多播委托action1 += action2;action1 += action3;action1.Invoke();}}class Student{public int ID { get; set; }public ConsoleColor PenColor { get; set; }public void DoHomework(){for (int i = 0; i < 5; i++){Console.ForegroundColor = this.PenColor;Console.WriteLine("Student {0} doing homework {1} hours", this.ID, i);Thread.Sleep(1000); //谁调用DoHomewrok方法谁就休眠1000mS}}}
}

委托还有另外一种高级使用方式,叫做隐式异步调用。

什么叫做隐式异步调用?我们可以将隐式异步调用分为2部分,即隐式、异步调用,接下来我们针对每一部分进行理解。

【隐式和显式】

  • 隐式指的是自动多线程,程序会自动创建分支线程辅助任务的执行。
  • 显式指的是用户使用Thread或Task手动创建分支线程进行任务的执行。

【同步和异步】

异步调用与同步调用是相对的,同步和异步这两个词在中文和英文中的意思有些差别。

同步指的是两个人做事情,你先做等你做完了我在你做的基础之上接着做,我做完了你再在我做的基础上接着做。

异步指的是两个人做事情,你做你的,我做我的,我们各不相干同时在做。

每一个程序运行起来之后都是内存当中的一个进程(Process),每一个进程都可能包含一个或者多个线程(Thread)。当程序启动的时候会生成一个进程,这个进程里面一定会有第一个运行起来的线程。这个第一个运行起来的线程就是这个进程或者说这个程序的主线程。进程中除主线程之外还可以有其它线程,主线程之外的线程叫做分支线程。

【同步调用和异步调用】

我们再来看一下方法的调用。当我们在同一个线程内去调用方法的时候,方法的执行是按照方法的调用先后顺序执行的,即前一个执行完了后一个才能得到执行。这种在同一个线程内依次执行的方法调用,叫做同步调用。

 

上图是典型的同步调用,图中红色部分表示主线程,其它颜色的表示在主线程中调用的不同方法。我们在主线程里调用了3个方法,主线程最先开始执行,然后调用第1个蓝色表示的方法。当第1个方法执行的时候,CPU的执行指针就进入到第1个方法里,而主线程就暂停在这个地方。直到第1个方法执行完成,执行指针返回到的主线程,主线程才可以继续执行。如此循环调用第2个、第3个方法,直到第3个方法执行完,执行指针再次返回到主线程,主线程执行完成后程序结束。

 

上图是典型的异步调用,图中红色部分表示主线程,其它颜色的表示在主线程中调用的不同方法。异步调用指的就是在不同的线程当中去调用方法,每个线程和另外的线程互不相干。一个线程的开始和结束不会影响到另外一个线程的开始和结束,而且不同的开始与结束时机又构成不同的运行组合。这就是我们对方法的异步调用,也叫做多线程调用。换句话来说,异步调用它的底层机理就是多线程。

 

【同步调用的三种方法】

同步调用指的就是在单线程里进行串行的调用,同步调用有三种形式:

  • 第一种是直接同步调用。直接同步调用就是用方法的名字来调用这个方法。
  • 第二种是单播委托间接同步调用。使用单播委托按顺序对方法进行间接的调用,使用Invoke的调用是同步调用,尽管是间接调用,但程序运行起来也是同步的。千万不要把直接、间接与同步、异步搞混了,这两组概念是相互独立的。
  • 第三种是多播委托间接同步调用。使用多播委托是将多个方法按顺序绑定到同一个委托上,使用Invoke的调用是同步调用,通过对这一个委托的调用实现对委托上绑定的方法按照其绑定的先后顺序顺序由前向后依次执行。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;namespace 委托_刘铁猛
{class Program{static void Main(string[] args){Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.White};Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Blue };Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Yellow };//第一种:直接同步调用//stu1.DoHomework();//stu2.DoHomework();//stu3.DoHomework();//实例化委托Action action1 = new Action(stu1.DoHomework);Action action2 = new Action(stu2.DoHomework);Action action3 = new Action(stu3.DoHomework);//第二种:单播委托间接同步调用//action1.Invoke();//action2.Invoke();//action3.Invoke();//第三种:多播委托间接同步调用action1 += action2;action1 += action3;action1.Invoke();for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main Thread {0}", i);Thread.Sleep(500);}}}class Student{public int ID { get; set; }public ConsoleColor PenColor { get; set; }public void DoHomework(){for (int i = 0; i < 5; i++){Console.ForegroundColor = this.PenColor;Console.WriteLine("Student {0} doing homework {1} hours", this.ID, i);Thread.Sleep(500); //谁调用DoHomewrok方法谁就休眠500mS}}}
}

上面代码的执行结果如下:

【异步调用的三种方法】

异步调用的指的就是使用多线程进行并行的调用,异步调用有三种形式:

  • 第一种是使用委托进行隐式异步调用。这是委托的另一种高级用法,使用委托的BeginInvoke方法的调用是异步调用。使用BeginInvoke时会自动生成一个分支线程,在这个分支线程里面调用委托中封装的方法。使用BeginInvoke调用委托中的方法,会发现主线程以及三个分支线程在调用后就开始并行的执行,谁都不会等着谁执行完再执行,这就是典型的异步调用。三个线程同时访问控制台的前景色属性,多个线程在访问同一个资源的时候就可能在争抢这个资源的时候发生冲突,现在我们看到的就是发生冲突的场景。为了避免这个冲突,有的时候我们会为线程加锁避免多线程程序当中的资源冲突。
  • 第二种是使用Thread的显式异步调用。使用比较古老的Thread手动声明多线程。
  • 第三种是使用Task的显式异步调用。使用更高级的Task手动声明多线程。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;namespace 委托_刘铁猛
{class Program{static void Main(string[] args){Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.White };Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Blue };Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Yellow };//第一种:使用委托进行隐式异步调用//Action action1 = new Action(stu1.DoHomework);//Action action2 = new Action(stu2.DoHomework);//Action action3 = new Action(stu3.DoHomework);//action1.BeginInvoke(null, null);//action2.BeginInvoke(null, null);//action3.BeginInvoke(null, null);//第二种:使用Thread的显式异步调用//Thread thread1 = new Thread(new ThreadStart(stu1.DoHomework));//Thread thread2 = new Thread(new ThreadStart(stu2.DoHomework));//Thread thread3 = new Thread(new ThreadStart(stu3.DoHomework));//thread1.Start();//thread2.Start();//thread3.Start();//第三种:使用Task的显式异步调用Task task1 = new Task(new Action(stu1.DoHomework));Task task2 = new Task(new Action(stu2.DoHomework));Task task3 = new Task(new Action(stu3.DoHomework));task1.Start();task2.Start();task3.Start();for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main Thread {0}", i);Thread.Sleep(500);}}}class Student{public int ID { get; set; }public ConsoleColor PenColor { get; set; }public void DoHomework(){for (int i = 0; i < 5; i++){Console.ForegroundColor = this.PenColor;Console.WriteLine("Student {0} doing homework {1} hours", this.ID, i);Thread.Sleep(500); //谁调用DoHomewrok方法谁就休眠500mS}}}
}

使用接口取代委托:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 委托_刘铁猛
{public delegate double Calc(double x, double y);    //定义委托class Program{static void Main(string[] args){IProductFactory pizzaFactory = new PizzaFactory();ToyCarFactory toyFactory = new ToyCarFactory();WrapFactory wrapFactory = new WrapFactory();Box box1 = wrapFactory.WrapProduct(pizzaFactory);Box box2 = wrapFactory.WrapProduct(toyFactory);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);}}interface IProductFactory{Product Make();}class PizzaFactory:IProductFactory{public Product Make(){Product product = new Product();product.Name = "Pizza";return product;}}class ToyCarFactory:IProductFactory{public Product Make(){Product product = new Product();product.Name = "Toy Car";return product;}}class Product{public string Name { get; set; }}class Box{public Product Product { get; set; }}class WrapFactory{public Box WrapProduct(IProductFactory productFactory){Box box = new Box();                      //准备一个BoxProduct product = productFactory.Make();  //获取一个产品box.Product = product;                    //把产品装到Box里面return box;                               //返回Box}}
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429518.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LintCode题集】Q6、Q64

最近开始刷LintCode上的题目&#xff0c;先从标签为容易的开始刷。今天刷的这两题目差不多为同一类型的题目&#xff0c;都是为按照一定的规则合并两个已经有序的数组。 [Q6] 描述&#xff1a; 合并两个排序的整数数组A和B变成一个新的数组。 样例&#xff1a; 给出A[1,2,3,4]&…

input标签的值只能两位小数_解决input只能输入金额类型的方案(金额输入框只能输入2位小数)...

欢迎加我技术交流QQ群 &#xff1a;811956471前言&#xff1a;最近在用uni-app框架&#xff0c;写一个项目(支付宝和微信小程序)遇到一个需求&#xff0c;要求金额输入框只能输入2位小数&#xff0c;且第一位数不能是 "."&#xff0c;只能是数字。发现用 input事件监…

C# winform中判断控件类型

C# winform中对控件类型的判断&#xff1a; public void UpdataControl(Control control, string data) {if (control is TextBox){doSomething1();}if (control is Label){doSomething1();}if (control is Button){doSomething1();}}

单元测试原来是这样的呼

我们要先创建一个界面&#xff1a; 显示的界面是这样的&#xff1a; 接下来我们来写java代码&#xff0c; 在输入框里的内容&#xff0c;点击button&#xff0c;将数据显示到上面的textview. 后面写测试用例&#xff0c;但我不知道哪里出错了&#xff0c;不知道是不是创建就出错…

python生成表达式_说说 Python 的生成器表达式

列表推导与生成器表达式都可以用于初始化元组、数组或其他类型的序列。但列表推导需要先建立一个完整的列表&#xff0c;然后再把这个列表传递到某个构造函数。而生成器表达式会逐个产出元素&#xff0c;这样显然能够节省内存。列表推导写法&#xff1a;codes [ord(symbol) fo…

C#中宏定义#define、预处理#if #else #endif的使用

C#中预处理的使用&#xff1a; 预处理指令并不会被编译为执行代码中的指令&#xff0c;但使用预处理指令可以选择编译程序中的哪部分代码。一般在调试代码时或在发布不同功能等级的软件版本中使用。 需要特别注意的是&#xff0c;宏定义必须在C#的.cs源文件最开头的位置定义&am…

华硕vm510l装固态硬盘_华硕VM510L拆机换固态硬盘

首先看下需要准备的东西&#xff0c;一台华硕笔记本&#xff0c;螺丝刀&#xff0c;固态硬盘。微信图片_201910051157221.jpg1.先把背面的螺丝全部卸掉。微信图片_20191005115722.jpg2.反过来&#xff0c;暴力拆键盘&#xff0c;从边缘部分开始撬。注意键盘下面有排线&#xff…

C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空

在C#中使用串口接收数据时发现&#xff0c;在完整的接收完一次数据后&#xff0c;还会再次进入串口接收事件。 在网上搜索资料发现其他开发者也有遇到该问题&#xff1a; [1] c#串口事件接受一次数据莫名其妙会触发两次 原文链接&#xff1a;https://www.52pojie.cn/threa…

js里的面向对象分析-(创建实例化对象)

ECMAScript 有两种开发模式&#xff1a;1.函数式(过程化)&#xff0c;2.面向对象(OOP)。面向对象的语言有一个标志&#xff0c;那就是类的概念&#xff0c;而通过类可以创建任意多个具有相同属性和方法的对象。但是&#xff0c;ECMAScript 没有类的概念&#xff0c;因此它的对象…

swift 隐藏状态栏_如何在Swift iOS应用中隐藏状态栏?

我想删除屏幕顶部的状态栏。这不起作用&#xff1a;func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: NSDictionary?)-> Bool{application.statusBarHidden truereturn true}我也尝试过&#xff1a;func application(applicati…

C#控件跨线程内容更新

在使用C#开发winform应用程序时&#xff0c;经常会碰到对控件跨线程访问造成的异常。在winform中UI线程和工作线程是分开的&#xff0c;但在实际使用中经常会需要在工作线程更新UI线程中创建的控件。 方法1&#xff1a;禁用跨线程访问控件检测 .NET默认开启了禁止跨线程控件访…

document.addeventlistener方法不执行_JUnit 5 测试方法的执行优先级

前言使用单元测试有时对方法的执行顺序有要求&#xff0c;而默认情况下测试方法的执行并非按照编写顺序&#xff0c;这就导致测试用例因执行顺序而导致的不通过。这里我使用的JUnit版本是5.6.2&#xff0c;下面讲述如何自定义测试方法的执行优先级。TestMethodOrder这个注解标注…

2异常处理_Java处理异常2种机制关键字区别解析

在异常处理的过程中,throws和throw的区别是?throws:是在方法上对一个方法进行声明,而不进行处理,而是向上传,谁调用谁处理.throw:是在具体的抛出一个异常类型.throws的栗子:throws的话,就是这个方法有可能会产生异常,而我只是将它声明出去,我自己不处理,如果有人调用的时候,可…

Scrapy——1

python3安装scrapy:http://www.cnblogs.com/Wananbo/p/6093969.html 运行scrapy时&#xff0c;弹出win32错误&#xff0c;然后用pip install pywin32 不行&#xff0c;实际上是缺少了pypiwin32转载于:https://www.cnblogs.com/tangbinghaochi/p/6593543.html

TL431的用法

TL431是可控精密稳压源。它的输出电压用两个电阻就可以设置从Vref&#xff08;2.5V&#xff09;到36V范围内的任何值。该器件的典型动态阻抗为0.2Ω&#xff0c;在很多应用中用它代替稳压二极管&#xff0c;例如&#xff0c;数字电压表&#xff0c;运放电路&#xff0c;可调压电…

个人作业2——英语学习APP的案例分析

产品&#xff1a;必应词典Android客户端 第一部分 调研&#xff0c; 评测 1、第一印象 一款app给人带来的第一印象&#xff0c;一是图标二是界面。微软必应词典的图标好似一本书&#xff0c;好看简洁又与词典相呼应&#xff0c;好评。二来其界面打开也很清爽&#xff0c;每日一…

AD16原理图.schdot中批量修改标签中的文本字体、大小、颜色

1&#xff09;使用鼠标左键区域选中需要修改的文本&#xff0c;或按住shift键使用鼠标左键选择分布在图中各处的需要修改的文本 2&#xff09;按住shift键&#xff0c;鼠标左键双击选中的任一文本&#xff0c;弹出如下的SCH Inspector弹窗 3&#xff09;在SCH Inspector弹窗中…

12v小型电机型号大全_鄂破碎机型号大全图,小型鄂破碎机价格

鄂破碎机&#xff0c;粗碎加工主力配置&#xff0c;因为使用频繁&#xff0c;很多案例都少不了&#xff0c;所以设备生产厂家有很多&#xff0c;但是随时鄂破碎机的机型更新&#xff0c;核心性能越来越完善&#xff0c;整机时产更高&#xff0c;而且环保性能更强悍。鄂破碎机型…

我的第一次Pascal程序

今天刚刚来学点Pascal语言&#xff0c;都怪我买的书大多是用Pascal语言写的&#xff0c;所以我只能试着学一点咯&#xff01; 来一段程序员最经典的Hello World&#xff01; 1 program exl_2; 2 begin 3 write(Hello World!); 4 end. 转载于:https://www.cnblogs.com/ECJTU…

C#中的前台线程和后台线程的区别

前台线程&#xff1a;应用程序必须运行完所有的前台线程才能退出&#xff0c;默认创建的线程都是前台线程。 后台线程&#xff1a;应用程序可以不必考虑后台线程是否已经运行完毕&#xff08;包括正常退出和异常退出&#xff09;&#xff0c;只要所有的前台线程结束&#xff0…