• 带你一步步的了解“C#事件”机制


    是什么

    本文讨论类型中定义的最后一种成员:事件
    定义了时间成员的类型允许类型通知其他对象发生了特定的事情。
    具体的说,定义了时间成员的类型能提供以下功能:

    • 方法能登记它对事件的关注
    • 方法能注销它对事件的关注
    • 事件发生时,登记了的方法将收到通知

    CLR事件模型以委托为基础。委托是调用回调方法的一种类型安全的方式。

    怎么用

    本文我们将通过一个小栗子来学习一下事件怎么使用:

    假定有个bolg平台可以订阅文章,用户A、B、C可以通过订阅或取消订阅来接收或者不接受此平台的文章。即,我是管理员,我在blog上发了一篇文章,那么订阅blog的用户就可以收到这篇文章了。

    下面我们来实现这个功能,顺便来学习下事件的使用:

    第一步:定义类型来容纳所有需要发送给事件通知者的附加信息

    约定:这种类型应该从System.EventArgs派生,而且类名以EventArgs结束。

    internal class BlogEventArgs : EventArgs
    {
        private readonly String author, content;
        private DateTime tdate;
    
        public BlogEventArgs(string author,string content,DateTime date)
        {
            this.author = author;
            this.content = content;
            this.tdate = date;
        }
    
        public string Author { get { return author;} }
        public string Content { get { return content; } }
        public DateTime TDate { get { return tdate;} }
    }
    

    第二步:定义事件成员

    约定:事件使用event关键字。每个事件成员要指定以下内容:可访问性标识符;委托类型;以及名称。

    internal class BlogManager
    {
        public event EventHandler<BlogEventArgs> NewBlog;
    }
    

    第三步:定义负责引发事件的方法来通知事件的登记对象

    约定:类要定义一个受保护的虚方法。引发事件时,类及其派生类中的代码回调用该方法。方法只接受一个参数,即BlogEventArgs对象

    protected virtual void OnNewBlog(BlogEventArgs e)
        {
            EventHandler<BlogEventArgs> temp = Volatile.Read(ref NewBlog);
            if (temp!=null)
            {
                temp(this, e);
            }
        }
    

    关于为什么要像上边这样写,只能说这样是线程安全的方式引发事件,其他方式可能会有线程方面的问题。

    第四步:定义方法将输入转化为期望事件

    BlogManager中,调用WriteNewBlog来指出写了一篇新博客

    public void WriteNewBlog(string author, string content, DateTime date)
        {
            BlogEventArgs e = new BlogEventArgs(author,content,date);
            OnNewBlog(e);
        }
    

    第五步:设计侦听事件的类型

    比如User类型想订阅或取消这个博客

    internal sealed class Reader
    {
        public Reader(BlogManager blogManager)
        {
            blogManager.NewBlog += blogManager_NewBlog;
        }
    
        void blogManager_NewBlog(object sender, BlogEventArgs e)
        {
            Console.WriteLine("读者已收到博客!");
            Console.WriteLine("作者:{0},内容:{1},发表时间:{2}",e.Author,e.Content,e.TDate.ToShortTimeString());
        }
    
        public void Unregister(BlogManager bmManager)
        {
            bmManager.NewBlog -= blogManager_NewBlog;
        }
    }
    

    最后一步使用起来

    class Program
    {
        static void Main(string[] args)
        {
            BlogManager bmManager = new BlogManager();
            Reader readerA  =new Reader(bmManager);
            bmManager.WriteNewBlog("1号作者", "这是我的第一篇文章", DateTime.Now);
            readerA.Unregister(bmManager);
            bmManager.WriteNewBlog("1号作者", "这是我的第二篇文章,应该收不到", DateTime.Now);
            Console.ReadKey();
        }
    }
    

    运行

    运行结果


    总结

    根据书本《CLR via C#》的小栗子自己更改了一点,希望对你有帮助。

  • 相关阅读:
    Spring用代码来读取properties文件
    单链表与双链表的区别
    为什么有些IP无法PING通但又能访问
    使用iperf3调试网络
    arm linux 移植 iperf3
    ZYNQ:PetaLinux工程更新HDF文件的脚本
    ZYNQ:使用PetaLinux打包 BOOT.BIN、image.ub
    ZYNQ:提取PetaLinux中Linux和UBoot配置、源码
    ZYNQ:使用 PetaLinux 构建Linux项目
    ZYNQ:使用SDK打包BOOT.BIN、烧录BOOT.BIN到QSPI-FLASH
  • 原文地址:https://www.cnblogs.com/kui0621/p/4918889.html
Copyright © 2020-2023  润新知