一.什么是委托
字面意思就是:这件事情我不亲自去做,而是委托别人去做
C#中的委托有点类似c/c++中的函数指针,但是C#中的委托就可以看作是函数指针的升级版
以下是c/c++的函数指针实例
#include<bits/stdc++.h>
using namespace std;
int (*Cal)(int a, int b);
//或者用typedef int (*Cal)将Cal定义为一种数据类型
int Add(int x, int y)
{
cout << "x+y=" << x + y << endl;
return x + y;
}
int main()
{
Cal = Add;//函数指针的调用
int x = 100;
int y = 100;
int c = Cal(x, y);
return 0;
}
先理解一个概念:一切皆地址
在计算机中所有的程序以及数据的存储都是有地址可循的,计算机组成原理就解释了程序的执行过程(将程序中的一条一条指令写入连续的内存中,并且用第一条指令的地址来表示它),所以函数和数据的区别就是,函数是寻找函数的地址,而数据是寻找数据的地址
直接调用:通过函数名调用,CPU通过函数名直接找到函数所在的首地址,然后调用函数
间接调用:通过函数指针调用,CPU先通过函数指针找到函数所在的地址然后调用函数
二.C#中的委托
C#中自带的委托
Fun<>:代参数的委托,一共有17中定义
Action :不带参数的委托
class Programme
{
static void Main(string[] args)
{
Complex complex = new Complex();
Action action = new Action(complex.PrintInfo);//注意这里只是要获得函数的地址名字所以不用加括号,加括号就是表示调用该函数了
action();
Func<int, int, int> fun = new Func<int, int, int>(complex.Add);
int test;
test = fun(1, 2);
Console.WriteLine(test);
}
}
class Complex
{
public void PrintInfo()
{
Console.WriteLine("PrintInfo has been used");
}
public int Add(int x, int y)
{
return x + y;
}
}
/*
* 输出结果
* PrintInfo has been used
3
*/
自定义委托
delegate关键字
从某种意义上来讲,委托也可以算是一种类,所以在定义的时候应该与类同一个级别,也就是写在命名空间下面
delegate int Cal(int x, int b);
class Programme
{
static void Main(string[] args)
{
Cal add = new Cal(Calculate.ADD);
Cal cut = new Cal(Calculate.Cut);
Cal mutiply = new Cal(Calculate.Mutiply);
Cal except= new Cal(Calculate.Except);
int x = 100;
int y = 200;
try
{
Console.WriteLine(add(x, y));
Console.WriteLine(cut(x, y));
Console.WriteLine(mutiply(x, y));
Console.WriteLine(except(x, 0));
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
class Calculate
{
public static int ADD(int x,int y)
{
return x + y;
}
public static int Cut(int x,int y)
{
return x - y;
}
public static int Mutiply(int x,int y)
{
return x * y;
}
public static int Except(int x,int y)
{
if (y == 0)
throw new Exception("y cannot be zero");
return x / y;
}
}
三.委托方法的应用
1.模板方法
便于函数重用,有利于减少bug,降低bug的修复成本
class Programme
{
static void Main(string[] args)
{
ProductFactory factory = new ProductFactory();
Func<Product> fun1 = factory.MakingPizza;
Func<Product> fun2 = factory.MakingToycar;
WarpFactory warpFactory = new WarpFactory();
Console.WriteLine(warpFactory.WarpProduct(fun1).Product.Name);
Console.WriteLine(warpFactory.WarpProduct(fun2).Product.Name);
}
}
class Box
{
public Product Product { get; set; }
}
class Product
{
public string Name { get; set; }
}
class WarpFactory
{
public Box WarpProduct(Func<Product> fun)
{
Product product =fun();//或者fun.invoke
Box box = new Box();
box.Product = product;
return box;
}
}
class ProductFactory
{
public Product MakingToycar()
{
Product product = new Product();
product.Name = "Toy car";
return product;
}
public Product MakingPizza()
{
Product product = new Product();
product.Name = "Pizza";
return product;
}
}
2.回调方法
回调的理解:假如你是公司的老板,你收到了很多实习生投递的简历,但是你要根据你的需求在合适的实践选择相应的员工
class Programme
{
static void Main(string[] args)
{
ProductFactory factory = new ProductFactory();
Func<Product> fun1 = factory.MakingPizza;
Func<Product> fun2 = factory.MakingToycar;
WarpFactory warpFactory = new WarpFactory();
Logger logger = new Logger();
Action<Product> action = logger.logCallBack;
Console.WriteLine(warpFactory.WarpProduct(fun1,action).Product.Name);
Console.WriteLine(warpFactory.WarpProduct(fun2,action).Product.Name);
}
}
class Logger
{
public void logCallBack(Product product)
{
Console.WriteLine("{0} has been warped at {1} and the price is {2}", product.Name, DateTime.UtcNow,product.Price);
}
}
class Box
{
public Product Product { get; set; }
}
class Product
{
public string Name { get; set; }
public double Price { get; set; }
}
class WarpFactory
{
public Box WarpProduct(Func<Product> fun,Action<Product> LoggerCallBack)
{
Product product =fun();//或者fun.invoke
Box box = new Box();
box.Product = product;
if(product.Price>50)
{
LoggerCallBack(product);
}
return box;
}
}
class ProductFactory
{
public Product MakingToycar()
{
Product product = new Product();
product.Name = "Toy car";
product.Price = 100;
return product;
}
public Product MakingPizza()
{
Product product = new Product();
product.Name = "Pizza";
product.Price = 10;
return product;
}
}
总结:难精通+易使用,在使用的时候还是要三思
四.委托的高级使用
多播(multicast)委托
一个委托内封装着不止一个方法
执行的顺序就是按照封装的顺序执行方法
class Programme
{
static void Main(string[] args)
{
Student stu1 = new Student() { ID = 1,Color = ConsoleColor.Red};
Student stu2 = new Student() { ID = 2, Color = ConsoleColor.Green };
Student stu3 = new Student() { ID = 3,Color = ConsoleColor.Blue};
Action action = stu1.DoHomeWord;
Action action2 = stu2.DoHomeWord;
Action action3 = stu3.DoHomeWord;
action += action2;
action += action3;
action();
}
}
class Student
{
public int ID { get; set; }
public ConsoleColor Color { get; set; }
public void DoHomeWord()
{
for(int i=0;i<5;i++)
{
Console.ForegroundColor = Color;
Console.WriteLine("{0} is Do Homework {1}", ID, i);
Thread.Sleep(1000);//多线程,就是所在的线程每次执行到这里都休息一秒
}
}
}
隐式异步调用
同步:你做完了,我接着做,相当于是流水线
程序开始执行的时候都会有一个主线程,其余的都叫做分线程,上图红线的就是主线程 ,其他颜色的线代表方法,不难看出每个方法执行的顺序是依次进行的,所以叫同步
异步:两个人互不相干
隐式异步调用
//将上述代码的action()改成如下代码即可显示为异步调用
action.BeginInvoke(null,null);
action2.BeginInvoke(null,null);
action3.BeginInvoke(null,null);
可以发现显示的颜色并不符合代码的要求:
因为多个线程都在抢占同一个资源,这样就会导致资源抢夺,所以解决的办法就是给线程加锁,这是以后的内容了
显示异步调用
Task task1 = new Task(stu1.DoHomeWord);
Task task2 = new Task(stu2.DoHomeWord);
Task task3 = new Task(stu3.DoHomeWord);
task1.Start();
task2.Start();
task3.Start();
Thread thread1 = new Thread(new ThreadStart(action));
Thread thread2 = new Thread(new ThreadStart(action2));
Thread thread3 = new Thread(new ThreadStart(action3));
thread1.Start();
thread2.Start();
thread3.Start();
也出现了和隐式一样的资源抢夺情况
五.拓展:Interface
本来一位接口是一个知识点,后来发现和c++中的纯虚函数相似,
interface可以代替委托
class Programme
{
static void Main(string[] args)
{
IProductFactory toy = new ToyFactory();
IProductFactory pizza = new PizzaFactory();
WarpFactory warpFactory = new WarpFactory();
Console.WriteLine(warpFactory.WarpProduct(toy).Product.Name);
Console.WriteLine(warpFactory.WarpProduct(pizza).Product.Name);
}
}
interface IProductFactory
{
Product Make();
}
class ToyFactory:IProductFactory
{
public Product Make()
{
Product product = new Product() { Name = "Toy Car"};
return product;
}
}
class PizzaFactory:IProductFactory
{
public Product Make()
{
Product product= new Product() { Name = "Pizza" };
return product;
}
}
class Box
{
public Product Product { get; set; }
}
class Product
{
public string Name { get; set; }
}
class WarpFactory
{
public Box WarpProduct(IProductFactory ipf)
{
Product product = ipf.Make();//或者fun.invoke
Box box = new Box();
box.Product = product;
return box;
}
}
总结
委托的使用要非常谨慎,所以在c#中可以合并Interface一并使用,java之所以在没有委托的情况下能发展就是用了Interface实现了委托的功能
文章来源地址https://www.toymoban.com/news/detail-841511.html文章来源:https://www.toymoban.com/news/detail-841511.html
到了这里,关于Unity学前C#:委托详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!