C#中的代理委托和event关键字

本文介绍了C#中代理的概念及使用方法,包括如何定义和使用代理,以及如何通过代理来实现方法的动态调用。此外,还详细解释了事件关键字的作用,并展示了如何结合代理与事件来处理多个事件响应函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

也叫作委托。事实上,代理就是用于定义指向方法的引用。
比如你在你眼前的程序中要调用另一部分程序的内容(方法或属性),但是,你不能保证函数名或者属性名不发生变化,或者根本程序不可见(不是public或者是DLL的程序)。那么就使用代理。
定义如下

        public delegate UInt32[] getDownLoadParam();
        public delegate void messgeFromDataLayer(Int32 info, Int32 info1, Int32 info2);

        getDownLoadParam m_getDownLoadParam;
        messgeFromDataLayer m_messgeFromDataLayer;

在模块初始化时为他们赋值。

            m_getDownLoadParam = GetDownLoadParam;
            m_messgeFromDataLayer = MessgeFromDataLayer;

函数名可以直接转化为代理类型的对象。这样,你就可以向普通函数一样调用他们了。

m_messgeFromDataLayer(1, 0, 0);

一个完整的使用如下

using System;
namespace sandbox
{
    class DelegateTest
    {
        public delegate void CompareDelegate(int a, int b);

        // 欲传递的方法,它与CompareDelegate具有相同的参数和返回值类型  

        public static void Compare(int a, int b)
        {
            Console.WriteLine((a > b).ToString());
        }



        public static void Main()
        {
            // 创建delegate对象  
            CompareDelegate cd = new CompareDelegate(DelegateTest.Compare);
            // 调用delegate  
            cd(1, 2);
        }
}

除了代理外,C#还有一个常见的语法糖。event关键字。上面代理可以让程序动态调用函数指针处理。但是,如果我们希望的处理函数不止一个,特别是对于界面上。所以,我们引入了event关键字。可以向中间添加若干个代理的实例,将依次调用。
event的声明是event+事件支持的代理名+event名。直接用event名就可以出发事件。一个event可以添加若干个事件处理的代理实例,但他们必须都是一个代理类型的。一个代理类型可以由多个代理的实例。

using System;

namespace sandbox
{
    class DelegateTest
    {

        public static void Main()

        {
            //创建事件源,并将事件处理程序进行注册
            EventSource src = new EventSource();
            src.OnClick += new EventSource.ClickHandler(MyFire1);
            src.OnClick += new EventSource.ClickHandler(MyFire2);
            src.Click();
            System.Console.ReadLine();
        }

        public static void MyFire1(object sender, ButtonClickArgs e)
        {
            Console.WriteLine(e.Clicker+"    hava been shot in 1");
        }
        public static void MyFire2(object sender, ButtonClickArgs e)
        {
            Console.WriteLine(e.Clicker+"    hava been shot in 2");
        }
    }
    class EventSource
    {
        public delegate void ClickHandler(object sender, ButtonClickArgs e);
        public event ClickHandler OnClick;
        public void Click()
        {
            OnClick(this, new ButtonClickArgs() { Clicker = "Signal" });
        }

    }

    public class ButtonClickArgs : EventArgs

    {
        public string Clicker;

    }
}

这种delegate和event共同使用的情景常用语界面的设计

如果你不使用代理,而执意要用public,那么在访问form的子类的对象的值类型成员时,编译器会给出CS1690警告:由于xxx是引用封送类的字段,访问上面的成员可能导致运行时异常。
这是因为form类是MarshalByRefObject的子类,该类旨在设计支持不同程序域的对象进行通信。一般来说,不同程序域的通信有两种方式,第一种就是直接传送对象的副本,另一种是使用代理。MarshalByRefObject使用的的是后一种。当有人要远程访问他的对象是,第一次他会向对方传递代理,然后如果对方调用该代理,就由己方的对象负责执行。
所以,如果你访问form类的对象A所包含的对象B的方法时,就将程序置于依赖远程对象执行的代码的风险之下,所以编译器会发送警告。解决的方法就是把对象B先复制到本地就可以了。

using System;

class WarningCS1690: MarshalByRefObject
{
   int i = 5;

   public static void Main() 
   {
     WarningCS1690 e = new WarningCS1690();
     e.i.ToString();   // CS1690

     // OK
     int i = e.i;//c#是system.int32的别名而已
     i.ToString();
     e.i = i;
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值