一、无题
委托(delegate)是函数指针的升级版
直接调用:通过函数名来调用函数,CPU通过函数名直接获得函数所在的地址并开始执行->返回
间接调用:通过函数指针来调用函数,CPU通过读取函数指针储存的值获得函数所在地址并开始执行->返回
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
//第一种委托类型
Calculator calculor = new Calculator();
Action action = new Action(calculor.Report);
calculor.Report(); //直接调用
action.Invoke(); //委托简介调用
action(); //简便写法
//第二种委托类型
Func<int, int, int> func1 = new Func<int, int, int>(calculor.Add);
Func<int, int, int> func2 = new Func<int, int, int>(calculor.Sub);
int x = 100;
int y = 200;
int z = 0;
z = func1.Invoke(x, y);
z = func1(x, y); //是上面的简写版
Console.WriteLine(z);
z = func2.Invoke(x, y);
z = func2(x, y); //是上面的简写版
Console.WriteLine(z);
}
}
class Calculator
{
public void Report()
{
Console.WriteLine("I have three number");
}
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;
}
}
}
结果
二、委托的声明(自定义委托)
委托是一种类(class),类是数据类型所以委托也是一种数据类型,它的声明方式与一般的类不同,主要是为了照顾可读性和c/c++传统
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public delegate double Calc(double x, double y);//写在Program外面,作为一个单独的类
class Program
{
static void Main(string[] args)
{
Type t = typeof(Action);
Console.WriteLine(t.IsClass);
Calcular calculator = new Calcular();
Calc calc1 = new Calc(calculator.Add);
Calc calc2 = new Calc(calculator.Sub);
Calc calc3 = new Calc(calculator.Mull);
Calc calc4 = new Calc(calculator.Div);
double a = 100, b = 200, 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);
}
}
class Calcular
{
public double Add(double x,double y)
{
return x + y;
}
public double Sub(double x,double y)
{
return x - y;
}
public double Mull(double x, double y)
{
return x * y;
}
public double Div(double x, double y)
{
return x / y;
}
}
}
结果
委托与所封装的方法必须“类型兼容”,即返回值的数值类型一致,参数列表在个数和数据类型上一致(参数名不需要一样)
三、委托的一般使用
实例:把方法当作参数传给另一个方法
1、模板方法,“借用”指定的外部方法来产生结果,相当于填空题,常位于代码中部,委托有返回值
2、回调方法,调用指定的外部方法,相当于流水线,常位于代码尾部,委托无返回值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
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 Product
{
public string Name { get; set; }
public double Price { get; set; }
}
class Logger //记录错误
{
public void Log(Product product)
{
Console.WriteLine("Product{0},create at {1}.Price is {2}",product.Name,DateTime.UtcNow,product.Price);
}
}
class Box
{
public Product Product { get; set; }
}
class WrapFactory
{
public Box WrapProduct(Func<Product> getProduct,Action<Product> logCallback)
{
Box box = new Box();
Product product = getProduct.Invoke();
if(product.Price >= 50)
{
logCallback(product);
}
box.Product = product;
return 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 ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Red };
Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Blue };
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 += action3;
action1();
}
}
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} hour(s).", this.ID, i);
Thread.Sleep(1000);//1秒
}
}
}
}
五、隐式异步调用
中英文差异,
同步:你做完我(在你的基础上)接着做(串联)
异步:咱们两个同时做(相当于汉语中的同时进行(并联)
同步调用与异步调用的对比
每一个运行的程序是一个进程(process)
每个进程可以有一个或者多个线程(thread)
同步调用是在同一线程内
异步调用的底层机理是多线程
串行==同步==单线程,并行==异步==多线程
例子:直接同步调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Red };
Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Blue };
stu1.DoHomework();
stu2.DoHomework();
stu3.DoHomework();
for (int i = 0; i < 10; i++)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Main thread {0}",i);
Thread.Sleep(1000);
}
}
}
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} hour(s).", this.ID, i);
Thread.Sleep(1000);//1秒
}
}
}
}
用委托的话就是间接同步调用,注意直接间接与同步异步是两个不同的概念,这里就不列出间接同步调用了
例子:隐式异步调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Red };
Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Blue };
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);
for (int i = 0; i < 10; i++)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Main thread {0}",i);
Thread.Sleep(1000);
}
}
}
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} hour(s).", this.ID, i);
Thread.Sleep(1000);//1秒
}
}
}
}
action.BeginInvoke()就是创建一个并行的线程
可以看到结果出现了学生与颜色不匹配,是因为几个并行在运行中出现资源冲突的情况,从而导致错误
例子:显式异步调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Red };
Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Blue };
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();
for (int i = 0; i < 10; i++)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Main thread {0}",i);
Thread.Sleep(1000);
}
}
}
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} hour(s).", this.ID, i);
Thread.Sleep(1000);//1秒
}
}
}
}
也可以使用Task方法来进显式调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Red };
Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Blue };
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(1000);
}
}
}
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} hour(s).", this.ID, i);
Thread.Sleep(1000);//1秒
}
}
}
}
委托才可以用到隐式异步调用