【C#进阶】C#中的委托、事件、回调函数、匿名函数和lambda表达式
C#中的委托、事件、回调函数、匿名函数和lambda表达式详细介绍
1.委托(delegate )
委托是一种类型,它可以存储对一个或多个方法的引用。它类似于C/C++中的函数指针,允许您将方法作为参数传递、存储和调用。
写法:
delegate <return_type> <delegate_name>( );
<return_type>
:表示委托所引用方法的返回类型。<delegate_name>
:表示委托的名称。<parameters>
:表示委托所引用方法的参数列表。
//以下是一个示例,说明如何定义和使用委托:
delegate void MyDelegate(string message);
class Program
{
static void Main()
{
MyDelegate del = new MyDelegate(ShowMessage);
del("Hello, world!");
}
static void ShowMessage(string message)
{
Console.WriteLine(message);
}
}
具体应用示例:
namespace WinFormsTest
{
/// <summary>
/// https://www.bilibili.com/video/BV1E14y1C7sm/?spm_id_from=333.337.search-card.all.click&vd_source=c17a6596481e29f0ffac1a21a026abff
/// 委托有什么用?
/// 1.将方法作为参数进行传递,有利于方法的解耦和隔离
/// 2.声明事件并进行注册
/// 定义委托的格式
/// 1.声明委托类型
/// 2.必须有一个方法包含了要执行的代码,这个方法必须符合委托类型签名
/// 3.创建一个委托实例
/// 4.必须调用invoke委托实例
/// </summary>
delegate void MyDelegate(); //定义一个委托,无参数和返回值
delegate string MyDelegate2(int a, int b);
public partial class delegateAndevent : Form
{
public delegateAndevent()
{
InitializeComponent();
//Type type = typeof(myDelegate);
//if (type.IsClass) MessageBox.Show("这是一个类");
//MyDelegate myDelegate = new MyDelegate(Method1);
下面两种方法都可以到委托中调用新的方法
//MyDelegate myDelegate2 = new MyDelegate(Method2);
//myDelegate += myDelegate2;
myDelegate += Method2; //在委托中添加方法
myDelegate -= Method2; //在委托中去除方法
//myDelegate.Invoke();
string result1 = myCal(5, 5, Add);
string result2 = myCal(5, 5, Multiple);
//MessageBox.Show(result1 + "..........." + result2);
}
void Method1()
{
MessageBox.Show("调用了方法1");
}
void Method2()
{
MessageBox.Show("调用了方法2");
}
String myCal(int a, int b, MyDelegate2 myDelegate)
{
return myDelegate(a, b);
}
//没有定义方法的修饰符时,private为默认,如果与namespace为同一级时则internal为默认
string Add(int a, int b)
{
return (a + b).ToString();
}
string Multiple(int a, int b)
{
return (a * b).ToString();
}
private void btnDelegate_Click(object sender, EventArgs e)
{
//C#中的两种强委托类型 Action<T1> , Func<T1,T2,T3,Tresult>
//Action 不返回值的委托类型 ,最多输入一个参数
Action<string> aa1 = (string a) => { MessageBox.Show(a + "强委托类型 Action<T1>,第一次"); }; //使用lambda表达式
Action<string> aa2 = a => { MessageBox.Show(a + "强委托类型 Action<T1>,第二次"); }; //使用lambda表达式
aa1 += aa2;
aa1.Invoke("使用了:");
//Func<T1,T2,T3,Tresult>
Func<string, string> func = h => h + "强委托类型 Func<T1,T2,T3,Tresult>,第一次";//使用lambda表达式
Func<string, string, string> func2 = (h, b) => h + "强委托类型 Func<T1,T2,T3,Tresult>" + b;//使用lambda表达式
//func += func2; //会报错,同一种类型的委托才可以
string funcResult1 = func.Invoke("使用了:");
string funcResult2 = func2.Invoke("使用了:", "第二次");
MessageBox.Show(funcResult1);
MessageBox.Show(funcResult2);
}
}
}
2.事件(event)
它用于建立一种通讯机制,使得对象可以通知系统某些事情已经发生,而无需知道具体会有哪些对象对此进行响应。
事件与委托: 事件是基于委托(一种特殊的类型安全的函数指针)的。
发布者与订阅者: 发布者负责声明和触发事件,订阅者负责订阅事件并定义响应逻辑。
事件定义: 使用event
关键字和相应的委托类型来定义事件。
public delegate void MyEventHandler();
public event MyEventHandler MyEvent;
事件订阅: 使用+=
操作符订阅事件,-=
操作取消事件订阅。
publisher.MyEvent += MyMethod;
publisher.MyEvent -= MyMethod;
EventArgs: 标准做法是通过一个继承自EventArgs
的类来传递事件数据。
事件访问器: 可以使用add
和remove
关键字可以自定义事件的订阅和取消订阅逻辑。
private MyEventHandler myEvent;
public event MyEventHandler MyEvent
{
add
{
myEvent += value;
}
remove
{
myEvent -= value;
}
}
匿名方法和Lambda: 可以使用匿名方法或Lambda表达式作为事件处理器。
自动事件: 可以使用event
关键字简化事件的定义和实现,这样编译器会自动为你实现事件访问器。
示例代码
下面是一个简单的例子,其中包括一个Clock
类(发布者)和一个Display
类(订阅者)。
using System;
using System.Threading;
// 定义委托(如果使用非泛型EventHandler,需要定义)
public delegate void TimerEventHandler(object sender, EventArgs e);
public class Clock
{
// 基于委托定义事件
public event TimerEventHandler Timer;
// 触发事件的方法
public void RunClock()
{
while (true)
{
Thread.Sleep(1000);
// 触发事件
Timer?.Invoke(this, EventArgs.Empty);
}
}
}
public class Display
{
// 事件处理方法
public void ShowTime(object sender, EventArgs e)
{
Console.WriteLine($"Current time: {DateTime.Now.ToLongTimeString()}");
}
}
class Program
{
static void Main(string[] args)
{
Clock clock = new Clock();
Display display = new Display();
// 订阅事件
clock.Timer += display.ShowTime;
// 启动时钟
clock.RunClock();
}
}
在这个例子中,Clock
类每秒触发一次Timer
事件,而Display
类订阅这个事件并显示当前时间。
具体应用示例:
namespace WinFormsTest
{
public partial class frmEvent : Form
{
/// <summary>
///事件的作用
///希望一个类的某些成员在发生某些变化时能够被外界观测到
///
/// 什么是事件?
/// 事件是委托的实例,限定了执行时的权限,只能在事件所在类的内部执行
/// 事件虽然是public,但是只能在类的内部被调用,因此需要在类的内部定义事件触发的方法
///
///
/// 定义事件的步骤
/// 1.定义事件的委托类型
/// 2.在类的内部声明事件
/// 3.声明事件
/// </summary>
//定义警报委托
public delegate void AlarmEventHandle();
internal class Alarm
{
public event AlarmEventHandle AlarmRaised; //在类的内部声明了一个事件
public void ShowAlarm()
{
MessageBox.Show("1.警报响起!");
Thread.Sleep(1000);
}
//定义事件触发的方法
public void OnAlarmRaised()
{
//if (AlarmRaised != null)
//{
// //AlarmRaised();
// AlarmRaised.Invoke();
//}
AlarmRaised?.Invoke();//上面if的写法等于这个
}
}
public frmEvent()
{
InitializeComponent();
}
private void btnEvent_Click(object sender, EventArgs e)
{
Alarm alarm = new Alarm(); //事件声明,然后订阅方法
alarm.AlarmRaised += alarm.ShowAlarm;
alarm.AlarmRaised += new Person().processAlarm;
alarm.AlarmRaised += () => { MessageBox.Show("3.马上处理结束...."); Thread.Sleep(1000); };
alarm.AlarmRaised += Method1;
//alarm.AlarmRaised -= Method1; //-=订阅移除
alarm.OnAlarmRaised();//触发事件
}
void Method1()
{
MessageBox.Show("4.处理完成!");
Thread.Sleep(1000);
}
public class Person
{
public void processAlarm()
{
MessageBox.Show("2.正在处理中.....");
Thread.Sleep(1000);
}
}
}
}
3.回调函数(callback)
回调函数用于在某个操作完成后执行特定的行为或通知。回调通常通过委托(Delegate)来实现,委托是C#中用于封装方法的对象。
委托(Delegate): 回调函数在C#中通常使用委托来表示。委托是一个类型安全的函数指针。
public delegate void MyCallback(string message);
异步回调: 在异步编程模型中,可以使用回调函数来处理异步操作的完成。
事件: 事件其实就是一种特殊类型的回调,它允许多个订阅者监听某个行为。
示例
以下是一个简单的回调函数示例:
using System;
public delegate void MyCallback(string message); // 定义委托
public class Operation
{
public void Execute(MyCallback callback)
{
// 执行某些操作...
// ...
// 操作完成后,调用回调函数
callback("Operation completed!");
}
}
//程序入口
public class Program
{
public static void Main()
{
Operation operation = new Operation();
// 定义回调函数
MyCallback callback = (message) =>
{
Console.WriteLine($"Callback invoked: {message}");
};
// 执行操作并传入回调函数
operation.Execute(callback);
}
}
在这个例子中,Operation
类有一个 Execute
方法,该方法接受一个回调函数(MyCallback
委托的实例)。当 Execute
方法的操作完成后,它会调用这个回调函数。
4.匿名函数和lambda表达式
匿名函数: 匿名函数是没有名称、只有函数体的函数。在C#中,你可以使用delegate
关键字来创建匿名函数。
delegate(int x) { return x * x; }
Lambda表达式: 是匿名函数的一种更简洁的表示方式,使用=>
符号来分隔参数和函数体。
x => x * x
参数类型推断: Lambda表达式通常可以推断参数类型,因此你不必显式声明它。
(x, y) => x + y
多语句Lambda: 使用花括号{}
,你可以在Lambda表达式中编写多条语句。
x => { Console.WriteLine(x); return x * x; }
捕获外部变量: 匿名函数和Lambda表达式可以捕获其作用域内的外部变量。
int y = 10;
Func<int, int> addY = x => x + y;
应用场景: 匿名函数和Lambda表达式常用于事件订阅、LINQ查询、异步编程等。
示例代码
使用匿名函数和Lambda表达式来订阅一个事件。
using System;
public class MyEventPublisher
{
public event Action<string> MyEvent;
public void RaiseEvent(string message)
{
MyEvent?.Invoke(message);
}
}
public class Program
{
public static void Main()
{
MyEventPublisher publisher = new MyEventPublisher();
// 使用匿名函数订阅事件
publisher.MyEvent += delegate(string message)
{
Console.WriteLine($"Received message using anonymous method: {message}");
};
// 使用Lambda表达式订阅事件
publisher.MyEvent += message => Console.WriteLine($"Received message using Lambda: {message}");
// 触发事件
publisher.RaiseEvent("Hello, World!");
}
}
精彩推荐:
【C#进阶一】C#中的数组(Array)、集合(ArrayList,Queue,Stack, HashList)、List<T>、字典(Dictionary<K,T>)和双向链表LinkedList
【C#进阶八】C#中的序列化与反序列化下(二进制序列化、XML序列化及JSON序列化)
【C#进阶】C#语法中一些常用知识点总结
【WinForm详细教程一】WinForm中的窗体、Label、TextBox及Button控件、RadioButton和CheckBox、ListBox
【WinForm详细教程三】WinForm中的NumericUpDown、PictureBox、RichTextBox及三种Timer控件
希望有所帮助,同时欢迎关注我,后面将更新更多相关内容!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)