首页 > 编程语言 >C# 事件

C# 事件

时间:2022-12-31 01:44:59浏览次数:34  
标签:DelegatePublish C# System value class OnChanged 事件 public

前言

本文只是为了复习,巩固,和方便查阅,一些知识点的详细知识会通过相关链接和文献标记出来。

为什么要用事件

要考虑这个问题之前,首先要知道使用委托的缺点,先看下面几段代码。其中包括了订阅DelegateSubscribe和发布DelegatePublish

namespace Event
{
    public class DelegatePublish
    {
        public int Value
        {
            get => _value;
            set
            {
                _value = value;
                Changed?.Invoke(_value);
            }
        }

        private int _value { get; set; }

        public Action<int> Changed;
    }

    public class DelegateSubscribe
    {
        public void ValueChanged(int value)
        {
            Console.WriteLine(value);
        }
    }
}

在主函数里面使用,一切顺利,它应该会被触发 Console.WriteLine(value);

// See https://aka.ms/new-console-template for more information

using Event;

var publish = new DelegatePublish();
var subscribe = new DelegateSubscribe();
publish.Changed += subscribe.ValueChanged;
publish.Value = 1;

一看没啥问题,订阅触发都正常,但这里有个可以操作的地方,就是这个changed可以被DelegatePublish以外的地方修改。如以下代码表示,实际上并没有值更新,但依旧可以触发。

// See https://aka.ms/new-console-template for more information

using Event;

var publish = new DelegatePublish();
var subscribe = new DelegateSubscribe();
publish.Changed = subscribe.ValueChanged;
publish.Changed.Invoke(1);

为了解决以上提到的问题,我们使用了event进行解决,只有直接持有这个事件的对象的类才可以调用事件,其他类只能使用+-和-=对这个事件进行添加或删除

public class DelegatePublish
{
    public int Value
    {
        get => _value;
        set
        {
            _value = value;
            OnChanged?.Invoke(this,new ValueArgs(_value));
        }
    }

    private int _value { get; set; }

    public event EventHandler<ValueArgs> OnChanged; 

    public class ValueArgs:EventArgs
    {
        public ValueArgs(int newValue)
        {
            NewValue = newValue;
        }

        public int NewValue { get; set; }
    }
}
void Publish_OnChanged(object? sender, DelegatePublish.ValueArgs e)

当然根据代码规范,其声明为object? sender表示委托对象的引用, EventArgs附带了数据

如果不喜欢参数e,还可以这么写,这样声明的就变成了 void Publish_OnChanged(object sender, DelegatePublish.ValueArgs newValue)

public event ChangedHandler OnChanged; 

public delegate void ChangedHandler(object sender, ValueArgs newValue);

事件的内部机制

DelegatePublish代码翻译成IL,可以发现 add_OnChanged remove_OnChanged分别表示 +=和-=。最后由addremove进行封装处理

.class public auto ansi beforefieldinit
  Event.DelegatePublish
    extends [System.Runtime]System.Object
{
  .field private class [System.Runtime]System.EventHandler`1<class Event.DelegatePublish/ValueArgs> OnChanged
   
  .method public hidebysig specialname instance void
    add_OnChanged(
      class [System.Runtime]System.EventHandler`1<class Event.DelegatePublish/ValueArgs> 'value'
    ) cil managed
  } // end of method DelegatePublish::add_OnChanged

  .method public hidebysig specialname instance void
    remove_OnChanged(
      class [System.Runtime]System.EventHandler`1<class Event.DelegatePublish/ValueArgs> 'value'
    ) cil managed
  
  } // end of method DelegatePublish::remove_OnChanged
  .event class [System.Runtime]System.EventHandler`1<class Event.DelegatePublish/ValueArgs> OnChanged
  {
    .addon instance void Event.DelegatePublish::add_OnChanged(class [System.Runtime]System.EventHandler`1<class Event.DelegatePublish/ValueArgs>)
    .removeon instance void Event.DelegatePublish::remove_OnChanged(class [System.Runtime]System.EventHandler`1<class Event.DelegatePublish/ValueArgs>)
  } // end of event DelegatePublish::OnChanged
} // end of class Event.DelegatePublish

这样我们知道了事件内部是怎么处理的,就可以自定义+=和-=了

public class DelegatePublish
    {
        public int Value
        {
            get => _value;
            set
            {
                _value = value;
                _OnChanged?.Invoke(this, new ValueArgs(_value));
            }
        }

        public event EventHandler<ValueArgs> OnChanged
        {
            add => _OnChanged = (ChangedHandler)Delegate.Combine(value, _OnChanged);
            remove => _OnChanged = (ChangedHandler)Delegate.Remove(_OnChanged, value)!;
        }

        public delegate void ChangedHandler(object sender, ValueArgs newValue);

        private int _value { get; set; }

        protected event ChangedHandler? _OnChanged;

        public class ValueArgs : EventArgs
        {
            public ValueArgs(int newValue)
            {
                NewValue = newValue;
            }

            public int NewValue { get; set; }
        }
    }

 

标签:DelegatePublish,C#,System,value,class,OnChanged,事件,public
From: https://www.cnblogs.com/yinghualuowu/p/17016140.html

相关文章

  • Selenium59-设计conftest
    pytest的conftest文件conftest文件的作用:一个专门存放fixture的配置文件。多个测试用例文件(test_*.py)的所有用例都需要用到一个前置/后置操作,如登陆退出,浏览器......
  • odoo CacheMiss 错误
    在进行调拨时遇到错误,stock.quant(12345,).product_uom_id然后没有其他任何提示,这种错误就比较难定位,到处打断点才定位到错误的位置,odoo针对计算字段compute,relat......
  • asm: gcc - c语言的内联汇编学习(linux_gcc_c)
    asm: gcc-c语言的内联汇编学习(linux_gcc_c)    一、基本说明 1、操作系统:rockylinux9[root@rockyc]#uname-a......
  • MySQL slave upgrade: Slave failed to initialize relay log info structure from th
    MySQL slaveafterupgradefrom 5.6.x to 5.7.x maythrowthefollowingerror:12mysql>STARTSLAVE;ERROR1872(HY000):Slavefailedtoinitiali......
  • buuoj-pwn-ciscn_2019_final_10
    buuoj-pwn-ciscn_2019_final_10总结题目分析glibcubuntu18.04,对应GLIBC2.27,对于这题,我们知道doublefree没检查就行逆向分析关键函数一第一个箭头所指没法绕过,随便......
  • C7下的docker 安装
    docker安装#step1:安装必要的一些系统工具sudoyuminstall-yyum-utilsdevice-mapper-persistent-datalvm2#Step2:添加软件源信息sudoyum-config-manager......
  • 【LeetCode】121. 买卖股票的最佳时机
    暴力破解法递归算法动态规划classSolution{public: intmaxProfit(vector<int>&prices){ size_tnPriceSize=prices.size(); intnMaxProfit=0; if(nP......
  • 浅谈C语言编译原理
    C语言我们在学习计算机学科时,往往最先接触到的编程语言是C,它是所有语言中,最接近底层的高级语言之一,因而它具有执行速度快的优点。但它又具有开发周期长和对于经验不足......
  • Zero-Copy
    "Zero-copy"describescomputeroperationsinwhichtheCPUdoesnotperformthetaskofcopyingdatafromonememoryareatoanotherorinwhichunnecessaryda......
  • [概率论与数理统计]笔记:1.2 随机事件的概率
    1.2随机事件的概率定义简单定义概率是随机事件发生的可能性大小的度量(数值)。频率可以作为概率的估计,但频率的稳定值不能作为概率的定义。一个事件的概率是由事件本......