C#委托小记C#委托学习笔记
- 一、什么是委托
- 二、委托的声明(自定义委托)
- 三、委托的一般使用
- 四、委托的高级使用
- 建议
一、什么是委托
- 委托(delegate)是函数指针的升级版
- 一切皆地址
- 变量(数据)是以某个地址为起点的一段内存中所存储的值
- 函数(算法)是以某个地址为起点的一段内存中所存储的一组机器语言指令
- 直接调用与间接调用
- 直接调用:通过函数名来调用函数,CPU通过函数名直接获得所在地址并开始执行->返回
- 间接调用:通过函数指针来调用函数,CPU通过读取函数指针存储的值获取函数所在地址并开始执行->返回
- Java中没有与委托相对应的功能实体
- 委托的简单使用
- Action委托
static void Main(string[] args)
{
Calcauator calcauator = new Calcauator();
Action action = new Action(calcauator.Report);//Report后没有(),在这里只需要方法名,加()表明想要调用这个方法
calcauator.Report();
action.Invoke();//委托.Invoke 方法
action();//也可以直接调用委托
}
class Calcauator
{
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;
}
}
- Func委托
static void Main(string[] args)
{
Calcauator calcauator = new Calcauator();
Action action = new Action(calcauator.Report);//Report后没有(),在这里只需要方法名,加()表明想要调用这个方法
calcauator.Report();
action.Invoke();//委托.Invoke 方法
action();//也可以直接调用委托
//Func委托
Func<int, int, int> func1 = new Func<int, int, int>(calcauator.Add);
Func<int, int, int> func2 = new Func<int, int, int>(calcauator.Sub);
int x = 100;
int y = 200;
int z = 0;
//写法1
//z = func1.Invoke(x,y);
//Console.WriteLine(z);
//z = func2.Invoke(x, y);
//Console.WriteLine(z);
//写法2
z = func1(x, y);
Console.WriteLine(z);
z = func2(x, y);
Console.WriteLine(z);
}
}
class Calcauator
{
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;
}
}
二、委托的声明(自定义委托)委托是一个函数指针的升级版,可以按照一定的约束指向目标方法,帮助我们完成对这些方法的间接调用
- 委托是一种类,可以用来声明变量和创建实例,类是数据类型所以委托也是一种数据类型
- 它的声明方式与一般的类不同,主要是为了照顾可读性和C/C++传统
- 注意声明委托的位置
namespace While
{
//声明委托
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;
//写法1
//c = calc1.Invoke(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);
//写法2
c = calc1(a, b);
Console.WriteLine(c);
c = calc2(a, b);
Console.WriteLine(c);
c = calc3(a, b);
Console.WriteLine(c);
c = calc4(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;
}
}
}
- 委托与所封装的方法必需“类型兼容”
- 实例:把方法当作参数传给另一个方法
- 正确使用1:模板方法,“借用”指定的外部方法来产生结果
1. 相当于“填空题”
2. 常位于代码中部
3. 委托有返回值
- 正确使用1:模板方法,“借用”指定的外部方法来产生结果
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
{
public Box WrapProduct(Func<Product>getProduct)//模板方法
{
Box box = new Box();//获取一个Box
Product 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 = "ToyCar";
return product;
}
}
- 正确使用2:回调(callback)方法 ,调用指定的外部方法,也叫好莱坞方法
1.相当于“流水线”
2. 常位于代码末尾
3. 委托无返回值
对于没有返回值的方法使用Action委托
class Program
{
static void Main(string[] args)
{
ProductFactory productFactory = new ProductFactory();
WrapFactory wrapFactory = new WrapFactory();
Logger logger = new Logger();
Action<Product> log = new Action<Product>(logger.Log);
Func<Product> func1 = new Func<Product>(productFactory.MakePizza);
Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);
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} creat 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
{
public Box WrapProduct(Func<Product>getProduct,Action<Product>logCallBack)//Func模板方法,Action展示回调方法了
{
Box box = new Box();//获取一个Box
Product product = getProduct.Invoke();//获取一个产品
if (product.Price>=50)
{
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 = "ToyCar";
product.Price = 100;
return product;
}
}
四、委托的高级使用
- 多播(multicast)委托:一个委托内部封装了不止一个方法
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1,Pencolor= ConsoleColor.Yellow }; //创建学生实例
Student stu2 = new Student() { ID = 2, Pencolor = ConsoleColor.Green };
Student stu3 = new Student() { ID = 3, Pencolor = ConsoleColor.Red };
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}Hour(s)",this.ID,i);
Thread.Sleep(1000);//线程睡1秒钟
}
}
}
- 隐式异步调用
- 异步:咱们两个同时做,相当于汉语中的同步进行
- 同步:你做完了我(在你的基础上)接着做
同步调用指的是在单线程里串行调用,异步调用指的是多线程并行调用
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1,Pencolor= ConsoleColor.Yellow }; //创建学生实例
Student stu2 = new Student() { ID = 2, Pencolor = ConsoleColor.Green };
Student stu3 = new Student() { ID = 3, Pencolor = ConsoleColor.Red };
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秒钟
}
}
}
- 显式异步调用
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1,Pencolor= ConsoleColor.Yellow }; //创建学生实例
Student stu2 = new Student() { ID = 2, Pencolor = ConsoleColor.Green };
Student stu3 = new Student() { ID = 3, Pencolor = ConsoleColor.Red };
Action action1 = new Action(stu1.DoHomework);//创建委托
Action action2 = new Action(stu2.DoHomework);
Action action3 = new Action(stu3.DoHomework);
显式异步调用,方式一
//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 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秒钟
}
}
}
建议
应当适时的使用接口(interface)取代一些对委托的使用
class Program
{
static void Main(string[] args)
{
IProductFactory pizzafactory = new PizzaFactory();
IProductFactory toycarfactory = new ToyCarFactory();
WrapFactory wrapFactory = new WrapFactory();
Box box1 = wrapFactory.WrapProduct(pizzafactory);
Box box2 = wrapFactory.WrapProduct(toycarfactory);
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
{
public Box WrapProduct(IProductFactory productFactory)
{
Box box = new Box();
Product product = productFactory.Make();
box.Product = product;
return box;
}
}
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 = "ToyCar";
return product;
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)