C# 事件Event

目录

事件的特点

事件的基本用法

事件练习

[补充::Action 委托函数](#补充::Action 委托函数)


在 C# 中,***事件(Event)***是一种特殊的委托,基于委托的并为委托提供一个发布/订阅的机制,可以说事件是一个具有特殊签名的委托。

事件的特点

  1. 只能在声明事件的类内部触发(保证封装性)
  2. 订阅者只能通过 +=-= 来订阅和取消订阅
  3. 支持多播(多个订阅者可以订阅同一个事件)
  4. 事件是委托的安全包装,防止外部直接调用或赋值

事件的基本用法

event是在委托上面加上关键字 加上之后在使用委托的时候会增加一些限制

这里以大学懒人舍友和怨种舍友为例,只有怨种下楼了,才可以给懒人室友带饭、拿快递:

怨种舍友类ToolMan

cs 复制代码
internal class ToolMan
{
    public string Name { get; set; }
    //构造函数
    public ToolMan(string name)
    {
        Name = name;
    }
    //定义一个委托
    public delegate void DownDelgate();
    //event 是在委托上面加上关键字  加上之后在使用委托的时候会增加一些限制 
    public event DownDelgate downDelgate = null;

    //创建了一个有参数(string参数类型)的事件  action
    public event Action<string> action;

    //调用事件的函数
    public void Down()
    {
        Console.WriteLine($"{Name}下楼了");
        downDelgate();
        action("怨种回来了");
    }
    //打印字符串显示函数
    public void Show(string str)
    {
        Console.WriteLine(str);
    }
}

懒人舍友类LazyMan

cs 复制代码
 internal class LazyMan
 {
     public string Name { get; set; }

     public LazyMan(string name) 
     {
         this.Name = name;
     }

     public void TakeFood()
     {
         Console.WriteLine($"{Name}买饭");
     }

     public void GetFoot()
     {
         Console.WriteLine($"{Name}拿快递");
     }
 }

主函数调用

先声明一些懒人和调用懒人类中所做的事的函数订阅在事件里:

cs 复制代码
static void Main(string[] args)
{
    ToolMan T = new ToolMan("怨种");
    LazyMan L1 = new LazyMan("小明");
    LazyMan L2 = new LazyMan("小张");
    LazyMan L3 = new LazyMan("小李");
    //+=订阅
    T.downDelgate += L1.TakeFood;
    T.downDelgate += L2.TakeFood;
    T.downDelgate += L3.TakeFood;
    //-=取消订阅订阅
    T.downDelgate -= L3.TakeFood;
cs 复制代码
 Console.WriteLine("怨种出发了");
怨种舍友还没有下楼,委托还不能发生,所以使用事件声明委托这里将不能提前执行会报错
 //T.downDelgate();
 //T.action("12300");直接订阅会报错
因此:在ToolMan类中的Down()函数调用写入这两个事件,当下楼函数执行时,事件也会发生。
 T.Down();
 }

这里 怨种工具人还没下楼 委托的事件也发生了 这不合理,这样写*T.downDelgate();*直接调用委托 会发现 工具人还没有下楼就执行了操作 事件还没有执行

怎么解决? 使用事件

报错说明: 事件的访问权限与使用场景不匹配

错误本质: C# 中,事件(event)是特殊的委托封装,为保证封装性:

  • 在定义事件的类(ToolMan)外部 ,事件只能通过 +=(订阅)、-=(取消订阅)操作,不能直接赋值(=)、调用或作为委托变量传递。
  • 代码里的 ToolMan.downDelgateToolMan.action是事件,却在类外部被当作普通委托用了(比如直接调用、赋值等),违反了事件的访问规则,所以编译器报错。

***解决方案:***这些事件都是怨种下楼之后才能操作的,且这些事件的调用只能在类本身访问使用,所以这里在ToolMan类中的Down()函数调用写入这两个事件,当下楼函数执行时,事件也会发生。

事件练习:

示例代码:

含有事件的类Class1,此处写一个函数Boilwater来判断水温,当水温达到95°,事件发生

cs 复制代码
internal class Class1
{
    //创建了一个事件
    public event Action<int> action;

    public void Boilwater()
    {
        for (int i = 0; i <= 100; i++)
        {
            if (i>=95)
            {
                action(i);
            }
        }
    }
}

报警器类Class3

cs 复制代码
 internal class Class3
 {
     public void MakeAi(int paras)
     {
         Console.WriteLine($"嘀嘀嘀:水已经{paras}");
     }
 }

液晶屏类Class2

cs 复制代码
internal class Class2
{
    public void ShowMsg(int param)
    {
        Console.WriteLine($"水温到了 当前水温{param}");
    }
}

主函数调用

cs 复制代码
static void Main(string[] args)
{
    Class1 c1= new Class1();
    Class2 c2= new Class2();
    Class3 c3= new Class3();

    c1.action += c2.ShowMsg;
    c1.action += c3.MakeAi;
    c1.Boilwater();
}

示例代码:

定义一个类Mom包含 KaiFan事件 和 cook函数

cs 复制代码
internal class Mom
{
    public event Action<string> KaiFan;

    public void cook()
    {
        Console.WriteLine("做饭");
        KaiFan("开饭");
    }
}

定义一个Dad类 包含虚方法eat

cs 复制代码
internal class Dad
{
    public virtual  void eat(string a)
    {
        Console.WriteLine(a+" 爸爸吃饭");
    }
}

定义一个Son类继承父类Dad 包含重写eat方法

cs 复制代码
internal class Son: Dad//继承Dad父类方法
{
    public override  void eat(string a)
    {
        Console.WriteLine(a + " 儿子吃饭");
    }
}

主函数订阅

cs 复制代码
static void Main(string[] args)
{
    Mom mom = new Mom();
    Dad dad = new Dad();
    Son son = new Son();
    //订阅
    mom.KaiFan += Show;
    mom.KaiFan  += dad.eat;
    mom.KaiFan += son.eat;
    //事件发生做饭
    mom.cook();

}
public static void Show(string str)
{
    Console.WriteLine(str);
}

补充:Action 委托函数

在 C# 中,Action 是一个预定义的泛型委托 ,位于 System 命名空间下,用于表示没有返回值的方法。它简化了委托的定义,无需手动声明委托类型,直接使用即可。

1. Action 的基本形式

Action 有两种常见形式:

  • 无参数的 Action:表示没有参数且无返回值的方法。

    cs 复制代码
    public delegate void Action();
  • 带参数的 Action<T> :泛型版本,支持 1~16 个参数(例如 Action<T1>Action<T1, T2> 等),同样没有返回值。

    cs 复制代码
    // 示例:带两个参数的 Action
    public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
相关推荐
终是蝶衣梦晓楼21 分钟前
HiC-Pro Manual
java·开发语言·算法
前端_yu小白40 分钟前
Vue2实现docx,xlsx,pptx预览
开发语言·javascript·ecmascript
Pocker_Spades_A1 小时前
从 0 到 1 开发图书管理系统:飞算 JavaAI 让技术落地更简单
java·开发语言·java开发·飞算javaai炫技赛
郝学胜-神的一滴1 小时前
对于类似std::shared_ptr但有可能空悬的指针使用std::weak_ptr: Effective Modern C++ 条款20
开发语言·c++·程序人生·系统架构
linux修理工1 小时前
使用 SecureCRT 连接华为 eNSP 模拟器的方法
服务器·开发语言·php
若水晴空初如梦2 小时前
QT聊天项目DAY17
开发语言·qt
Murphy_lx2 小时前
C++ stdset 与 stdmultiset 深度比较
开发语言·c++
样子20182 小时前
PHP 之使用HTMLPurifier过滤XSS
开发语言·前端·php·xss
时光追逐者2 小时前
C#/.NET/.NET Core优秀项目和框架2025年7月简报
c#·.net·.netcore