CSharp之 委托(delegate)与事件(event)

一、认识委托

可以把delegate理 解成C中的函数指针,它允许传递类A的方法M给类B的对象,使得类B的对象能够调用这个方法M,说白了就是可以把方法当作参数传递。

但 delegate和函数指针还是有些区别的,并且更具优势:

首先,函数指针只能指向静态函数,而delegate既可以引 用静态函数,又可以引用非静态成员函数。在引 用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。

其次,与函数指针相 比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法, 你无须担心delegate会指向无效地址或者越界地址。

二、定义一个委托(delegate)

1、声明一个delegate对象,它应当与你想要传递的方法具有相同的参数名和返回值类型

2、创建delegate对象,并将你想要传递的函数作为参数传入 

3、在要实现异步调用的地方,通过上一步创建的对象来调用方法

三、定义一个事件

1、定义对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。 

2、定义事件参数类,此类应当从System.EventArgs类派生,如果事件不带参数,这一步可以省略。 

3、定义事件处理方法,它应当与delegate对象具有相同的参数和返回值类型。 

4、用event关键字定义事件对象,它同时也是一个delegate对象。 

5、用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。 

6、在需要触发事件的地方用调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。名字是可以是OnEventName 

7、在适当的地方调用事件触发方法触发事件。 

四、.NET Framework中标准委托与事件

.NETFramework中,标准的委托已经定义在命名空间中:

namespace System
{
    public delegate void EventHandler(object sender, EventArgs e);
}

.NETFramework类库中所有事件均基于EventHandler。

.NETFramework中事件参数的定义必须继承自EventArgs:

public class CustomEventArgs:EventArgs
{

}

.NETFramework事件发布,可以有以下几种方式:

//自定义参数方式
public delegate void CustomEventHandler(object sender,CustomEventArgs e);
public event CustomEventHandler CustomEvent;

//标准参数方式
public event EventHandler CustomEvent;

//标准委托泛型方式
public event EventHandler<CustomEventArgs> CustomEvent;

综上所述,.NETFramework事件定义与发布一般遵循如下规范:

1、来源类定义:主要包含委托与事件引发定义

public class CustomEventSource
{
}

2、在类CustomEventSource中定义委托,例如:

public delegate void CustomEventHandler(object sender,CustomEventArgs e);

3、基于标准参数类(EventArgs),定义参数类,例如:

public class CustomEventArgs:EventArgs
{
}

4、在类CustomEventSource中定义事件,例如:

public event CustomEventHandler CustomEvent;

5、在类CustomEventSource中定义引发事件,例如:

public void RaiseCustomEvent()
{
    //定义参数,或者直接new EventArgs()
    CustomEventArgs e = new CustomEventArgs();

    //委托类型事件响应
    if(CustomEvent != null)
    {
        CustomEvent(this, e);
    }  
}

6、订阅类定义:包括事件处理方法定义、注册、取消注册,例如:

public class CustomEventListener
{
}

7 、在类CustomEventListener中添加事件处理方法,例如:

private void InputAction(object sender, EventArgs e)
{
    Console.WriteLine("您按了{0}键", Console.ReadKey().KeyChar.ToString());
}

8、在类CustomEventListener中添加事件订阅,例如:

public void Subscrible(CustomEventSource customEventSource)
{
    customEventSource.InputEvent += new CustomEventListener().InputAction;
}

9、在类CustomEventListener中添加事件取消订阅,例如:

public void UnSubscrible(CustomEventSource customEventSource)
{
    customEventSource.InputEvent -= new CustomEventListener().InputAction;
}

10、定义事件使用,例如:

class Program
{
   static void Main(string[] args)
   {
       //创建事件源对象
       CustomEventSource evtSource = new CustomEventSource();

       //创建监听对象
       CustomEventListener evtListen = new CustomEventListener();

       //订阅事件
       Console.WriteLine("订阅事件");
       evtListen.Subscrible(evtSource);

       while (true)
       {
           evtSource.RaiseInputEvent();
       }
   }
}

五、一个完整的自定义事件

键盘输入或为单个字符或为字符串,自定义事件(ReadKeyEvent)将根据输入判定是字符还是字符串,完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyReadKey
{
    public class ReadKeyEventSource
    {
        public event EventHandler<ReadKeyEventArgs> ReadKeyEvent; 
        public void RaiseReadKeyEvent()
        {
            while (true)
            {
                string str = Console.ReadLine();
                ReadKeyEvent(this, new ReadKeyEventArgs(str)); 
            }
        }
    }
    public class ReadKeyEventListener
    {
        private void DoKeyEvent(object sender, ReadKeyEventArgs e)
        {
            Console.WriteLine(e.KeyboardValue.Length == 1 ? "您输入了字符:'{0}',ASCII码(" + ((int)e.KeyboardValue[0]).ToString() + ")" : "您输入了字符串:'{0}'", e.KeyboardValue);
        }
        public void Subscrible(ReadKeyEventSource readKeyEventSource)
        {
            readKeyEventSource.ReadKeyEvent += new ReadKeyEventListener().DoKeyEvent;
        }

        public void UnSubscrible(ReadKeyEventSource readKeyEventSource)
        {
            readKeyEventSource.ReadKeyEvent -= new ReadKeyEventListener().DoKeyEvent;
        }
    }
    public class ReadKeyEventArgs : EventArgs
    {
        string _keyboardValue;

        public ReadKeyEventArgs(string keyValue)
        {
            if (keyValue.Length == 1)
            {
                this._keyboardValue = keyValue[0].ToString();
            }
            else
            {
                this._keyboardValue = keyValue;
            }
        }

        public string KeyboardValue
        {
            get
            {
                return _keyboardValue;
            }
        }
    }
}

//调用程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyReadKey
{
    class Program
    {
        static void Main(string[] args)
        {
            ReadKeyEventSource rkes = new ReadKeyEventSource();

            ReadKeyEventListener rkel = new ReadKeyEventListener();

            Console.WriteLine("请输入字符或字符串(输入后回车):");
            rkel.Subscrible(rkes);

            while (true)
            {
                rkes.RaiseReadKeyEvent();
            }
        }
    }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值