【C#进阶】C#中的委托、事件、回调函数、匿名函数和lambda表达式

这篇具有很好参考价值的文章主要介绍了【C#进阶】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的类来传递事件数据。

事件访问器: 可以使用addremove关键字可以自定义事件的订阅和取消订阅逻辑。

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控件

希望有所帮助,同时欢迎关注我,后面将更新更多相关内容!文章来源地址https://www.toymoban.com/news/detail-735700.html

到了这里,关于【C#进阶】C#中的委托、事件、回调函数、匿名函数和lambda表达式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# 中的委托和事件机制

    在C#中,委托和事件是非常重要的概念,用于实现程序中的回调和事件处理。在这里,我们将介绍C#中委托和事件机制的基础知识和用法。 委托是一种类似于C/C++函数指针的概念,它允许将方法作为参数传递到其他方法中,以实现回调函数的功能。委托是一种类型,它可以表示

    2023年04月21日
    浏览(26)
  • C#中的委托(Delegate)和事件 (Event)详解与使用范例

    最近天气晴雨不定,你因为害怕打游戏时忘记在下雨时收衣服或者在天晴时把衣服挂出去,于是你委托好友小明在天气发生变化时打电话通知你,这就是一种委托. 下面是这种委托的实例代码 以上代码的输出为 值得一提的是,如下代码为创建一个继承自Delegate类的名为XiaoMing的子类

    2023年04月12日
    浏览(31)
  • C#匿名方法增加、删除委托

    匿名方法给我们带来了方便,那么如何增加删除匿名方法中附加的委托(事件)呢 一般写法: 1 2 3 4 this .Loaded += (sender, e) =       {              //Do something       }; 进化写法: 1 2 3 4 5 6 7 this .Loaded += new   RoutedEventHandler(FormulaAssign_Loaded); void   FormulaAssign_Loaded( objec

    2024年02月11日
    浏览(25)
  • C# 中的回调函数

    引言 回调函数是一种在编程中常用的概念,它在 C# 中扮演着重要的角色。本文将介绍回调函数的概念、语法和应用,并讨论如何设计优化和重用回调函数,以及它们在并发编程中的用途。 回调函数是指将一个函数作为参数传递给另一个函数,并在被调用函数执行完毕后,再

    2024年02月20日
    浏览(26)
  • python 匿名函数(lambda函数)

    Python中的匿名函数是指没有命名标识符的函数,通常被称为lambda函数。与普通函数不同,它们是一种更加简洁的方式来编写小型临时函数。在Python中,匿名函数使用 lambda 来定义,其语法如下: 其中, arguments 表示函数参数,可以是一个或多个,多个参数之间用逗号分隔

    2024年02月02日
    浏览(41)
  • C# 匿名方法和Lambda表达式

    1.匿名方法的演变 匿名方法是为了简化委托的实现,方便调用委托方法而出现的,同时,匿名方法也是学好lambda表达式的基础。在委托调用的方法中,如果方法只被调用一次,这个时候我们就没有必要创建具名方法,从而用匿名方法更为方便。 下面一段代码是声明并使用了一

    2024年02月15日
    浏览(29)
  • 使用std::function 来实现回调函数、委托的功能

    std::function 可以用来实现回调函数和委托的功能。下面是一个回调函数的示例: 在上述示例中,我们定义了回调函数 printText ,这个函数接受一个字符型指针参数,并打印出这个字符串。然后,我们定义了函数 processText ,该函数接受两个参数:文本和一个 std::function 类型的对

    2024年02月09日
    浏览(28)
  • python匿名函数Lambda

    Lambda函数也被称为匿名(没有名称)函数,它直接接受参数的数量以及使用该参数执行的条件或操作,该参数以冒号分隔,并返回最终结果。为了在大型代码库上编写代码时执行一项小任务,或者在函数中执行一项小任务,便在正常过程中使用lambda函数。 argument_list是参数列表,

    2024年02月16日
    浏览(39)
  • lambda匿名函数

    问题: 什么是lambda函数?它有什么好处?举例说明 解答 含义 在Python中,不通过def来声明函数名字,而是通过 lambda 来定义的函数称为匿名函数,即函数没有具体的名称,你可以理解为 一句话写一个函数 Lambda表达式是Python中一类特殊的定义函数的形式,从语义上讲,它们

    2024年02月15日
    浏览(48)
  • 【C#学习笔记】委托与事件 (从观察者模式看C#的委托与事件)

    转载请注明出处:🔗https://blog.csdn.net/weixin_44013533/article/details/134655722 作者:CSDN@|Ringleader| 主要参考: 委托(C# 编程指南) 事件介绍 C# 中的委托和事件简介 Delegate 类 Exploring the Observer Design Pattern微软技术文章翻译 委托是一种 引用类型 ,表示对具有特定参数列表和返回类型

    2024年02月04日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包