c#委托(精简版,好理解)
首先,我们要知道,委托它是一种类。结果如下:所以它确实是一种类!我们新定义一个除法方法我们来新建一个自定义委托注意要声明在类平级的地方,这个委托名字叫Calc,第一个double是返回值类型,后面两个是参数类型。
1、什么是委托
在C#中,委托是c/c++ 中函数指针的升级版!
我们先在c语言编写一段代码:
#include<stdio.h>
int Add(int a,int b){
return a+b;
}
int Sub(int a,int b){
return a-b;
}
int main(){
int x = 100;
int y = 200;
int z=0;
z = Add(x,y);
printf("%d+%d=%d\n",x,y,z);
z = Sub(x,y);
printf("%d-%d=%d",x,y,z);
return 0;
}
运行结果如下:
接下来我们来声明一个函数指针
typedef int(* Calc)(int a,int b);
这里我们声明了一个函数指针类型,这个类型的名字叫Calc,它要求传入的参数类型为两个Int类型,限制了返回值类型为int类型。
下面我们来尝试使用它:
#include<stdio.h>
typedef int(* Calc)(int a,int b);
int Add(int a,int b){
return a+b;
}
int Sub(int a,int b){
return a-b;
}
int main(){
int x = 100;
int y = 200;
int z=0;
Calc Fun1 = &Add;
Calc Fun2 = ⋐
z = Fun1(x,y);
printf("%d+%d=%d\n",x,y,z);
z = Fun2(x,y);
printf("%d-%d=%d",x,y,z);
return 0;
}
运行结果如下:
我们发现两次结果一样,说明代码没有错误。在上面的代码中,我们发现直接调用方法和间接通过指针调用方法的结果是一样的。
直接调用:CPU 通过函数名直接获得函数所在地址并开始执行。
间接调用:CPU 通过读取函数指针存储的值获得函数所在地址并开始执行。
我们要首先理解一个概念,一切皆地址:
我们知道,java语言和c#语言都是c++语言发展而来,但是java语言为了安全性,不允许程序员直接访问地址,舍弃了与指针相关的东西,但是c#语言却通过委托来保留了与函数指针这部分对应的功能。
2、c#中的委托
先在c#中编写如下代码:
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
}
}
class Calculator
{
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#中已经为我们准备好了两个委托,现在我们来使用一下:
2.1 Action 委托
我们在Main方法中编写如下代码:
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Action action = new Action(calculator.Report);
}
这里我们声明了 Action 的委托 aciton ,它接收一个返回值为void的且无参数方法
所以在构造函数中传入了calculator实例的Report方法。
接下来我们尝试使用直接调用和间接调用
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Action action = new Action(calculator.Report);
calculator.Report();
action.Invoke();
}
结果如下:
结果完全一样!
委托的间接调用时通过 : 委托名.Invoke(); 也就是: aciton.Invoke():
其实它还有一种简便的写法: 委托名(); 也就是: action();
2.2 Func 委托
Func<int, int, int> func = new Func<int, int, int>(calculator.Add);
这种委托接收的是有返回值的函数,对函数接收的参数没有要求!他还是一种泛型委托。
三个int表示最后一个int是返回值类型,前面的全部都是参数类型。所以这里传入的是Add方法(Sub方法也可以)
我们来运行一下:
int x = 100;
int y = 200;
Func<int, int, int> func = new Func<int, int, int>(calculator.Add);
int z = func.Invoke(x, y);
Console.WriteLine(z);
结果如下:
public double chufa(double a, double b)
{
return a / b;
}
2.3 自定义委托
首先,我们要知道,委托它是一种类。
我们来验证一下:
Type t = typeof(Action);
Console.WriteLine(t.IsClass);
结果如下:
所以它确实是一种类!
我们新定义一个除法方法
public double chufa(double a, double b)
{
return a / b;
}
我们来新建一个自定义委托
public delegate double Calc(double a , double b);
注意要声明在类平级的地方,这个委托名字叫Calc,第一个double是返回值类型,后面两个是参数类型。我们来使用一下:
double a = 100;
double b = 200;
Calc c = new Calc(calculator.chufa);
double d = c.Invoke(a, b);
Console.WriteLine(d);
返回结果:
2.4 多播委托
多播委托意思就是一个委托内部封装了不止一个方法。
编写如下代码:
using System;
using System.Threading;
namespace EventExample
{
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();
}
}
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);
}
}
}
}
结果:
像这种一个委托封装一个方法的形式叫单播委托。
接下来我们来看多播委托:
action1 += action2;
action1 += action3;
action1.Invoke();
这里的+=就相当于把后面的委托封装到前面的委托里面
现在的action1就相当于有了三个想法。
这里我执行后效果跟原来一样,但是我只执行了action1,用一个委托封装了多个方法!而且执行顺序是按照封装顺序来的。
2.5 委托的隐式异步调用
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)