C# 从1到Core--委托与事件(二)

简介:  委托与事件在C#1.0的时候就有了,随着C#版本的不断更新,有些写法和功能也在不断改变。本文温故一下这些改变,以及在NET Core中关于事件的一点改变。

3. 通过方法避免风险

  很自然想到采用类似Get和Set的方式避免上面的问题。既然委托可以像变量一样赋值,那么也可以通过参数来传值,将一个方法作为参数传递。、

    public class HRWithAddRemove
    {
        private SendDelegate sendDelegate;
        public void AddDelegate(SendDelegate sendDelegate)
        {
            this.sendDelegate += sendDelegate; //如果需要限制最多绑定一个,此处可以用=号
        }
        public void RomoveDelegate(SendDelegate sendDelegate)
        {
            this.sendDelegate -= sendDelegate;
        }
        public void SendMessage(string msg)
        {
            sendDelegate(msg);
        }
    }

经过改造后的HR,SendDelegate方法被设置为了private,之后只能通过Add和Remove的方法进行方法绑定。


4.模拟多播委托机制

通过上面委托的表现来看,委托就像是保存了一个相同方法名的集合 List<SendDelegate> ,可以向集合中添加或移除方法,当调用这个委托的时候,会逐一调用该集合中的各个方法。


例如下面的代码( 注意这里假设SendDelegate只对应一个方法 ):

public class HR1
{
    public void Delegate(SendDelegate sendDelegate)
    {
        sendDelegateList = new List<SendDelegate> { sendDelegate }; //对应=
    }
    public void AddDelegate(SendDelegate sendDelegate)
    {
        sendDelegateList.Add(sendDelegate); //对应+=
    }
    public void RomoveDelegate(SendDelegate sendDelegate)
    {
        sendDelegateList.Remove(sendDelegate);//对应-=
    }
    public List<SendDelegate> sendDelegateList;
    public void SendMessage(string msg)
    {
        foreach (var item in sendDelegateList)
        {
            item(msg);
        }
    }
}

二、C#1.0 引入事件

  1.简单事件

  如果既想使用-=和+=的方便,又想避免相关功能开闭的风险怎么办呢?可以使用事件:

    public class HRWithEvent
    {
        public event SendDelegate sendDelegate;
        public void SendMessage(string msg)
        {
            sendDelegate(msg);
        }
    }

只是将SendDelegate前面添加了一个event标识,虽然它被设置为public,但如下代码却会给出错误提示: 事件“HRWithEvent.sendDelegate”只能出现在 += 或 -= 的左边(从类型“HRWithEvent”中使用时除外)

 hr.sendDelegate = senderZS.Send;
 hr.sendDelegate("偷偷的发一条");

2.事件的访问器模式

  上文为委托定义了Add和Remove方法,而事件支持这样的访问器模式,例如如下代码:

    public class CustomerWithEventAddRemove
    {
        private event SendDelegate sendDelegate;
        public event SendDelegate SendDelegate
        {
            add { sendDelegate += value; }
            remove { sendDelegate -= value; }
        }
        public void SendMessage(string msg)
        {
            sendDelegate(msg);
        }
    }

可以像使用Get和Set方法一样,对事件的绑定与移除进行条件约束。


 3. 控制绑定事件的执行

 当多个委托被绑定到事件之后,如果想精确控制各个委托的运行怎么办,比如返回值(虽然经常为void)、异常处理等。


第一章第4节通过一个List<SendDelegate> 模拟了多播委托的绑定。 会想到如果真能循环调用一个个已绑定的委托,就可以精确的进行控制了。那么这里说一下这样的方法:

    public class HRWithEvent
    {
        public event SendDelegate sendDelegate;
        public void SendMessage(string msg)
        {
            //sendDelegate(msg);  此处不再一次性调用所有
            if (sendDelegate != null)
            {
                Delegate[] delegates = sendDelegate.GetInvocationList(); //获取所有已绑定的委托
                foreach (var item in delegates)
                {
                    ((SendDelegate)item).Invoke(msg); //逐一调用
                }
            }
        }
    }

 这里通过Invoke方法逐一调用各个Delegate,从而实现对每一个Delegate的调用的控制。若需要异步调用,则可以通过BeginInvoke方法实现(.NET Core之后不再支持此方法,后面会介绍。)

((SendDelegate)item).BeginInvoke(msg,null,null);

4. 标准的事件写法

  .NET 事件委托的标准签名是:

void OnEventRaised(object sender, EventArgs args);

返回类型为 void。 事件基于委托,而且是多播委托。 参数列表包含两种参数:发件人和事件参数。 sender 的编译时类型为 System.Object。


 第二种参数通常是派生自 System.EventArgs 的类型(.NET Core 中已不强制要求继承自System.EventArgs,后面会说到)。


 将上面的例子修改一下,改成标准写法,大概是下面代码的样子:

public class HRWithEventStandard
{
    public delegate void SendEventHandler(object sender, SendMsgArgs e);
    public event SendEventHandler Send;
    public void SendMessage(string msg)
    {
        var arg = new SendMsgArgs(msg);
        Send(this,arg); //arg.CancelRequested 为最后一个的值   因为覆盖
    }
}
public class SendMsgArgs : EventArgs
{
    public readonly string Msg = string.Empty;
    public bool CancelRequested { get; set; }
    public SendMsgArgs(string msg)
    {
        this.Msg = msg;
    }
}


目录
相关文章
|
1月前
|
C#
c# Gridview 点击checkbox 触发的事件
c# Gridview 点击checkbox 触发的事件
|
5天前
|
C#
c#委托详解
c#委托详解
7 0
|
1月前
|
C#
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
|
1月前
|
C#
C# 禁止ComboBox滚动事件细谈
C# 禁止ComboBox滚动事件细谈
|
2月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
87 0
|
2月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
170 2
|
4月前
|
存储 C# C++
C#进阶-委托(Delegrate)
类似于 C 或 C++ 中函数的指针,委托是C#的函数指针,是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。本篇文章我们将讲解C#里委托的类型及如何使用。委托的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
28 0
|
5月前
|
Java C# C++
【从Java转C#】第八章:委托、lambda、事件
【从Java转C#】第八章:委托、lambda、事件
|
5月前
|
C#
C#中的委托
C#中的委托
21 0