C语言中的函数指针:
一切皆地址:
程序的本质是变量+算法
变量是以变量名对应内存地址为起点的一段内存,其所存储的数据就是变量里的数据,这段内存的大小由变量的数据类型决定->变量是地址。
函数是以函数名对应的内存地址为起点的一段内存,这段内存存储的不是某个值,而是一组机器语言的指令,CPU按照这组指令一条条执行,完成我们函数中所包含的算法->函数是地址。
直接调用与间接调用的本质:
直接调用:
CPU通过函数名找到这段地址,然后执行指令,执行完最后一条,CPU返回到调用者那里去。
间接调用:
CPU通过某个指向某函数的函数指针来间接调用函数,函数指针是一个变量,它存储函数名所对应的那个地址,找到地址后,后面是一样的。
C#通过委托来保留C语言中的间接调用功能,Java则完全舍弃了这部分功能,禁止直接访问内存。
委托就是函数指针的升级。
C语言中需要先声明函数指针类型,才能使用这个类型。
而C#类库中已经为我们准备好了很多可以直接使用的委托类型。
常用的有Action(无返回值的方法专用),Function等
举个例子,我们建一个计算器类:
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;
}
}
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Action action = new Action(calculator.Report);
calculator.Report();//直接调用
action.Invoke();//间接调用(使用action委托)
action(); //间接调用的简洁版
}
}
代码分析,Calculator是计算器类,我们建立它的实例calculator然后,
建立Action实例action,它的构造函数要求我们输入一个:
参数列表为空,无返回值(返回值为void)的方法。
Report方法满足这个条件。
所以:
Action委托是专门应对——无返回值(返回值为void)的方法的。
对于有返回类型和有参数的方法,我们使用Func委托:
Func<>委托有若干的重载,前面的是参数类型,最后一项是返回值类型。
在这里我们用第二种。
要求我们在Func的构造函数里填写匹配的方法,我们写入Add和Sub方法。
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Func<int, int, int> func1 = new Func<int, int, int>(calculator.Add);
Func<int, int, int> func2 = new Func<int, int, int>(calculator.Sub);
int z = 0;
z = func1.Invoke(100, 200);//间接调用(使用Func委托),还可以简写为z = func1(200,100);
Console.WriteLine(z);
z = func2.Invoke(100, 200);//间接调用(使用Func委托)
Console.WriteLine(z);
}
}
委托是个类,我们来验证一下
using System;
using System.Collections.Generic;
namespace CustomizeDelegate
{
class Program
{
static void Main(string[] args)
{
Type t = typeof(Action);
Console.WriteLine(t.IsClass);//返回true,说明Action委托是类
}
}
}
程序结果:
true
所以证明委托是个类。
自定义一个委托:
参数类型,返回类型必须一一对应(名称可以不同)
委托类,因为是类,与其他类平级,所以声明在命名空间里,他的声明格式是仿照函数指针。
public delegate double Calc{double x, double y};
定义一个计算机类Calculator
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;
}
}
创建Calculator类实例calculator ,然后创建Calc委托的实例calcAdd等等。
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Calc calcAdd = new Calc(calculator .Add);
Calc calcSub = new Calc(calculator .Sub);
Calc calcMul = new Calc(calculator .Mul);
Calc calcDiv = new Calc(calculator .Div);
double result = 0;
result = calcAdd.Invoke(100, 200);//间接调用(使用Calc委托)
Console.WriteLine(result);
result = calcSub(100, 200);//间接调用(使用Calc委托)
Console.WriteLine(result);
result = calcMul(100, 200);//间接调用(使用Calc委托)
Console.WriteLine(result);
result = calcDiv(100, 200);//间接调用(使用Calc委托)
Console.WriteLine(result);
}
}
结果是: