委托回调是刚接触c#时最头疼的东西,老看老忘,遂整理一下现在对委托回调的理解。如有错误,请指出,感谢。

委托

C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。 

回调函数

回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

注意:定义的回调方法签名必须和委托对象一致,这是因为将方法绑定到委托时,编译器会检测他们的兼容性。不符合的话回报编译错误。就比如有一个方法要传入String类型,我们给它传递了一个int类型一样。

委托回调的作用:

调用时,委托可以调用多个方法。 这被称为多播。 若要向委托的方法列表(调用列表)添加其他方法,只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托。

回调函数可以把调用者与被调用者分开,所以调用者不关心谁是被调用者以及被调用者如何实现。它只需知道存在一个具有特定原型和限制条件的被调用函数。

代码示例:

public static void add(int a,int b)
{
    Console.WriteLine(a + b);
}
public static void multiply(int a,int b)
{
    Console.WriteLine(a * b);
}
static void Main(string[] args)
{
    int x = 1, y = 3;
    add(x, y);
    multiply(x, y);
    Console.ReadLine();
}

委托版:

//申明委托
public delegate void CalculateDelegate(int a, int b);
public static CalculateDelegate calculateDelegate;
//回调函数1
public static void add(int a,int b)
{
    Console.WriteLine(a + b);
}
//回调函数2
public static void multiply(int a,int b)
{
    Console.WriteLine(a * b);
}
static void Main(string[] args)
{
    int x = 1, y = 3;
    calculateDelegate = add;//绑定事件
    calculateDelegate += multiply;//多播
    calculateDelegate(x, y);          
    Console.ReadLine();
}

项目代码中遇到的委托回调示例

 事件发送者的主要工作就是监听,当监听到某一临界条件成立后,将事件告知事件接收者,由事件接收者完成后续动作。

示例1:窗口间传输数据

我做的标注工具,仿labelimg,在子窗口输入label以后,要传回主窗口。我用的是委托(不太清楚有没有其他好的方法)。

c获取LUA的回调 回调c#_数据

(1)事件发布者:子窗口

//申明事件的委托
public delegate void LabelNameDelegate(string labelName);
public LabelNameDelegate labelNameDelegate;

//引发事件的函数
private void btnOK_Click(object sender, EventArgs e)
{
    ...
    if (labelNameDelegate != null)
        labelNameDelegate(txtLabelName.Text.Trim());
    ...
}

(2)事件监听者:主窗口

//绑定事件
form.labelNameDelegate = addLabelToList;
//事件发生后的处理程序
 private void addLabelToList(string labelName)
{
    listboxLabel.Items.Add(labelName);
    ...
}

示例2:相机获取图像

在实际工作中,较常接触到的例子是相机的委托回调。相机的代码由相机厂商提供,我们只需调用其中的方法,而不用知道它是如何处理数据的。比如相机都会提供开始捕获的委托,该委托会传回图像数据,我们再对图像数据进行处理,比如直接把它显示在picturebox上。我们要写的是对应的得到图像后的处理函数,比如下面的GetImage,其参数和委托参数相同。最重要的是要将事件绑定,即Camera.Acqfun = GetImage。此时,一旦Camera的开始获取图像事件触发,图像就会传到GetImage函数中,并由其处理,显示在picturebox中。

(1)事件发布者:相机

打开相机,会触发camera类的StartAcq(开始获取图像)事件。事件订阅者利用方法GetImage(从图像数据中获取图片)处理事件。

public class Camera
{
        //1. 声明事件的委托
    public delegate void AcqDelegate(IntPtr imgPtr,int imgHeight,int imgWidth);
        //2. 声明事件
    public AcqDelegate AcqFun;
        //3. 编写引发事件的函数(事件的触发一般在某个函数中)
    public override bool StartAcq()
    {
            ...
            if(AcqFun!=null)
            AcqFun();
        ...
    }
}

 事件订阅者

public class xxx
{
    //4. 编写事件处理程序
    public void GetImage(IntPtr imgdata, int imageHeight, int imageWidth)
    {
        ...
    }
    public void StartCamera(Camera.AcqDelegate acqfun)
    {  
    //5. 注册事件处理程序
    camera.AcqFun = acqfun;
    //6. 触发事件
    camera.StartAcq();
    }
}

 触发事件

StartCamera(GetImage);