委托(Delegate) 是一种类型安全的函数指针,它允许你将方法(函数)作为参数传递、存储或动态调用。可以将委托看作成一个存放方法的容器,需要用到的时候可以在调用容器中的方法。
Delegate,Action,Func,Event的(ConsoleApplication)Demo1:
public class ExerciseDelagate { public delegate void MyDelegate(); //声明一个无参数无返回值的委托 public MyDelegate myDelegate; //初始化委托 public Action<string> myAction; //直接初始化参数为string 无返回值的委托 public Func<DateTime, string> myFunc; //直接初始化参数为DateTime 返回值string委托 ,返回类型为最后一个参数类型 public event MyDelegate myEventDelegate;//event是基于委托的,初始化事件 public void DelegateExample() { Console.Write("我是Delegate委托赋予的方法\n"); } public void ActionExample(string str) { Console.Write($"我是Action委托赋予的方法-{str}\n"); } public string FuncExample(DateTime dateTime) { return string.Format("我是Func委托赋予的方法-{0}\n", dateTime); } public void DelegateExample2() { Console.Write("我是Delegate多播委托的实例\n"); } public void EventExample() { Console.Write("我是Event实例方法\n"); } public void CallEvent() { myEventDelegate?.Invoke();//用?.invoke()可以防止myEventDelegate没绑定方法直接调用 } } public class Demo { static void Main(string[] args) { ExerciseDelagate exdelegate = new ExerciseDelagate(); exdelegate.myDelegate = exdelegate.DelegateExample; //绑定实例方法,方法的参数和返回值要与委托一致 exdelegate.myDelegate += exdelegate.DelegateExample2; //可以绑定多个方法,称为多播委托 用+= 增加,-=减少 exdelegate.myDelegate(); //调用委托,相当于调用DelegateExample和DelegateExample2方法。 //exdelegate.myDelegate?.Invoke(); 也可以写成这样,与上面执行结果一致 exdelegate.myAction = exdelegate.ActionExample; //绑定实例方法,方法的参数和返回值要与委托一致 exdelegate.myAction("Hello"); //调用委托,相当于调用ActionExample方法。 exdelegate.myFunc = exdelegate.FuncExample; //绑定实例方法,方法的参数和返回值要与委托一致 Console.Write(exdelegate.myFunc(DateTime.Now)); //调用委托,相当于调用FuncExample方法获取返回值再打印出来。 //exdelegate.myEventDelegate = exdelegate.EveneExample; //注意事件不能用'='绑定方法,过不了编译 只能用+=或者-= exdelegate.myEventDelegate += exdelegate.EventExample; //原因是event关键字保证了对应类内部的安全和封装,避免覆盖类里的绑定方法 //exdelegate.myEventDelegate(); //注意事件也不能由外部调用,过不了编译 exdelegate.CallEvent(); //调用CallEvent方法间接去实现事件 Console.ReadLine(); } }
在平时开发中,应用到委托的场景有窗体之间的传值等,如在Form1中的业务逻辑需要传值取构建Form2,Form2执行完逻辑用户在关闭Form2后需要返回值给Form1。窗体传值Demo2:
我们想在Form关闭后Form1的标题值改成返回值,Form1代码:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 form2= new Form2(DateTime.Now); //构造Form2
form2.dataReturned += Form2DataReturn; //事件绑定Form2DataReturn方法
form2.Show();
}
private void Form2DataReturn(string obj)
{
this.Text = obj;
}
}
Form2代码:
public partial class Form2 : Form
{
private DateTime dateTime;
private string dataTimeStr;
public event Action<string> dataReturned; //初始化事件 无返回值有string类型参数
public Form2(DateTime now)
{
InitializeComponent();
this.FormClosed += Form2_FormClosed; //Form2关闭窗体事件绑定方法,也可以在前端绑定,效果一样,不过前端绑定这条代码会自动放在InitializeComponent()里
this.dateTime = now;
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
dataReturned?.Invoke(dataTimeStr); //将处理后的业务结果作为参数放回
}
/// <summary>
/// 窗体加载事件方法,这段就是在前端绑定的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form2_Load(object sender, EventArgs e)
{
//处理返回值的业务逻辑,这里简单化
dataTimeStr= this.dateTime.ToString("yyyy-MM-dd");
}
}
点击打开Form2按钮 Form2关闭后,Form1标题就改变了
日志记录Demo3:
Form1代码:
public partial class Form1 : Form
{
public static Action<string> addLog;
public Form1()
{
InitializeComponent();
addLog = WriteListViewLog;
}
private void button1_Click(object sender, EventArgs e)
{
Form2 form2= new Form2(DateTime.Now); //构造Form2
form2.dataReturned += Form2DataReturn; //事件绑定Form2DataReturn方法
form2.Show();
}
private void Form2DataReturn(string obj)
{
this.Text = obj;
}
/// <summary>
/// listView 日志写入方法
/// </summary>
private void WriteListViewLog(string logStr)
{
//InvokeRequired判断是否在UI线程上执行,如果不在则用控件.invoke将指定的委托排队到创建该控件的UI线程的消息队列中,并在该UI线程上执行该委托。
if (this.InvokeRequired)
{
this.listView1.Invoke(new Action<string>(WriteListViewLog),logStr);
}
ListViewItem listViewItem = new ListViewItem(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
listViewItem.SubItems.Add(logStr);
this.listView1.Items.Add(listViewItem);
}
}
Form2:
public partial class Form2 : Form
{
private DateTime dateTime;
private string dataTimeStr;
public event Action<string> dataReturned; //初始化事件 无返回值有string类型参数
public Form2(DateTime now)
{
InitializeComponent();
this.FormClosed += Form2_FormClosed; //Form2关闭窗体事件绑定方法,也可以在前端绑定,效果一样,不过前端绑定这条代码会自动放在InitializeComponent()里
this.dateTime = now;
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
dataReturned?.Invoke(dataTimeStr); //将处理后的业务结果作为参数放回
}
/// <summary>
/// 窗体加载事件方法,这段就是在前端绑定的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form2_Load(object sender, EventArgs e)
{
Form1.addLog("成功打开Form2窗体");
//处理返回值的业务逻辑,这里简单化
dataTimeStr = this.dateTime.ToString("yyyy-MM-dd");
}
}
打开FORM1 打开FOMR2