C#中的代理与事件

C#代理实际上类似于C++中的函数指针,因为C#中不存在指针,所以用代理可以完成一些原来在C++中用函数指针完成的操作,例如传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。但与函数指针相比,delegate有许多函数指针不具备的优点。首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。在引用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。其次,与函数指针相比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法,你无须担心delegate会指向无效地址或者越界地址。 

    实现一个delegate是很简单的,通过以下3个步骤即可实现一个delegate:

1. 声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。 
    声明一个代理的例子:
    public delegate int MyDelegate(string message);

2. 创建delegate对象,并将你想要传递的函数作为参数传入。 
     创建代理对象的方法:
    1). MyDelegate myDelegate = new MyDelegate(实例名.方法名);
    2). MyDelegate myDelegate = new MyDelegate(类名.方法名);
注:如果需要代理的方法是一个static静态方法的话,采用第2种方式,否则采用第1种方式。

3. 在要实现异步调用的地方,通过上一步创建的对象来调用方法。 
    可以直接使用代理调用代理所指向的方法:
    myDelegate(向方法传递的参数);

    下面是一些需要注意的事情:
“代理”(delegate)(代表、委托):“代理”是类型安全的并且完全面向对象的。
1)在C#中,所有的代理都是从System.Delegate类派生的(delegate是System.Delegate的别名)。
2)代理隐含具有sealed属性,即不能用来派生新的类型。

2)代理隐含具有static属性,不能与static一起修饰。

3)代理最大的作用就是为类的事件绑定事件处理程序。
4)在通过代理调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。
(5
)在代理实例中可以封装静态的方法也可以封装实例方法。
6)在创建代理实例时,需要传递将要映射的方法或其他代理实例以指明代理将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。
7)只有当两个代理实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。
8)多个代理实例可以形成一个代理链,System.Delegate中定义了用来维护代理链的静态方法Combion,Remove,分别向代理链中添加代理实例和删除代理实例。
9)因为定义委托基本上是定义一个新类,所以可以在定义类的任何地方定义委托,既可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。如delegate int MyDelegate();而在类的方法中调用MyDelegate d = new MyDelegate(MyClass.MyMethod);来实例化自定义代理的实例。
10)代理三步曲:
a.生成自定义代理类:delegate int MyDelegate();
b.然后实例化代理类:MyDelegate d = new MyDelegate(MyClass.MyMethod);
c.最后通过实例对象调用方法:int ret = d(); 

例1.

1.代理声明
     class A
    {
        public   delegate void MyDelegate(string str,int index);      
        public static void show(string str,int index)
        {
            Console.WriteLine(str + index.ToString());    

        }       
      
    }

2.代理实例化

  class Program
    {
        static void Main(string[] args)
        {
         
            A.MyDelegate md = new A.MyDelegate(A.show);//代理含有static属性,所以A.MyDelegate是类名.代理。

//show函数是static类型,所以A.show是类名.函数名
            md("hello word", 1);
            Console.Read();
           
           
        }
    }
二、多播代理
上面我们讲的代理是一个代理对象指向一个方法,在调用该代理对象的时候就会调用它所指向的方法。多播代理就是为一个代理挂接上多个方法,当执行该代理的时候就会依次执行该代理上挂接的方法。

多播代理的声明与上面讲得基本上一样:
  
[public/private] delegate void <代理名称>(<参数列表>);
  
   只有一点不一样的就是,多播代理所指向的方法应当是void类型
1.代理声明

   class A
    {
        public   delegate void MyDelegate(string str,int index);      
        public static void show1(string str,int index)
        {
            Console.WriteLine(str + index.ToString());    

        }
        public static void show2(string str, int index)
        {
            Console.WriteLine(str + index.ToString());

        }       
    }

2.代理实例化

   class Program
    {
        static void Main(string[] args)
        {
         
            A.MyDelegate md = new A.MyDelegate(A.show1);
            md += new A.MyDelegate(A.show2);

            md("hello word", 1);
        
            Console.Read();
           
           
        }
    }

 在上面这个例子当中有两个方法(show1和show2)符合MyDelegate代理的签名,如果要把这两个方法挂接到我们一个代理变量上去的话,就得用 += 运算符了。
     MyDelegate md = new MyDelegate(show1);
    md += new MyDelegate(show2);
   这里的md代理变量上先挂接了show1方法,再挂接show2方法。当执行md("hello world",22)的时候会先调用show1方法,再调用show2方法。
   事件本身就是一种多播代理

三、事件
C#中的事件就是代理的一个变量。它和属性、方法一样,都是类的成员。只不过事件是指向一个方法,当事件被触发时,就会执行对象的相关方法。(简单说也就是在事件里面绑定了另外一个方法)
事件的这种对方法的引用并不是写死在代码里面的,而是可以进行更改的。辟如:我们在DotNet中按钮的OnClick事件,它可以指向符合OnClick事件签名的任何一个方法。
1.事件的定义使用event关键字:
  public event CryHandler DuckCryEvent;
  
   其中的CryHandler是一个delegate。从上面的代码我们可以看出来:事件就是一个代理类型的变量。
  private delegate void CryHandler();

2.指定事件处理程序:
   指定事件处理程序就是为事件挂接方法的过程。
  DuckCryEvent +=new CryHandler(Cry);
  public void Cry()
    {
        Console.WriteLine("我是一只小鸭,呀依呀依呀....");
    }
   
3.执行事件
  执行事件就是调用事件所指向方法的过程。
一般对事的执行代码写在相应的方法或属性中,如果方法或属性被调用时就触发事件。
  public void BeShaked()
    {
        DuckCryEvent();
    }
   
4.完整的例子:
  //事件用到的代理,以般以×××Handler的格式进行命名
   private delegate void CryHandler();
   //玩具小鸭的类
    class Duck
    {
       //定义小鸭的唱歌事件
        public event CryHandler DuckCryEvent;
        public Duck()
        {
           //把小鸭唱歌的事件挂接到Cry方法上
            DuckCryEvent +=new CryHandler(Cry);
        }
        //小鸭唱歌事件对应的处理方法
        public void Cry()
        {
            Console.WriteLine("我是一只小鸭,呀呀呀....");
        }
        //小鸭被摇动
        public void BeShaked()
        {
           //执行事件
            DuckCryEvent();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
             //买一只小鸭
            Duck d = new Duck();
            //摇一摇小鸭,它就会调触发小鸭的Cry事件,小鸭就会唱歌
            d.BeShaked();
            Console.Read();
           
            
        }
    }

四、事件在ASP.NET中的举例
页面视图代码    <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />

cs页面代码

    protected void Page_Load(object sender, EventArgs e)
    {
        Button1.Click += new EventHandler(Button1_Click);
        Button1.Click += new EventHandler(XiXi);

    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Write("Button1Click<br>");

    }
    protected void XiXi(object sender, EventArgs e)
    {
        Response.Write("XiXi<br>");
    }

    protected void Haha(object sender, EventArgs e)
    {
        Response.Write("HaHa<br>");
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值