XuGang

记录一个程序员的成长

 

再探委托与事件


委托

在这里补充两个对委托运用得比较少的示例:

一、将委托作为参数传递,然后再调用;

二、使用委托调用内部类中的方法;

 

示例一:委托作为参数

委托作为参数.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace 委托作为参数
{
    
class 计算器
    {
        
public delegate int delCalculate(int a, int b);

        
// 将委托作为参数
        public void Fun(int a, int b, delCalculate cal)
        {
            
if (cal != null)
            {
                Console.WriteLine(cal(a,b));
            }
        }

        
// 加法
        public int Add(int a, int b)
        {
            
return a + b;
        }
        
// 减法
        public int Reduce(int a, int b)
        {
            
return a - b;
        }
    }

    
class Run
    {
        
static void Main(string[] args)
        {
            计算器 js 
= new 计算器();

            
//调用加法
            计算器.delCalculate d1 = new 计算器.delCalculate(js.Add);
            js.Fun(
20,10, d1); //将委托作为参数

            
//调用减法
            js.Fun(20,10,new 计算器.delCalculate(js.Reduce));
        }
    }
}


示例二:委托调用内部类的方法

委托调用内部类的方法.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace 委托调用内部类的方法
{
    
class Person
    {
        
public delegate void myDelegate(string str);

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

        
//内部类的调用
        public class InnerClass
        {
            
public void SubFun(string str)
            {
                Console.WriteLine(str);
            }
        }
    }

    
class Program
    {
        
static void Main(string[] args)
        {
            Person p 
= new Person();
            
//内部委托的实例化(用类名调用)
            Person.myDelegate pm1 = new Person.myDelegate(p.Fun);
            pm1(
"内部委托调用的方法");

            
//内部类 InnerClass
            Person.InnerClass pc = new Person.InnerClass();
            Person.myDelegate pm2 
= new Person.myDelegate(pc.SubFun);
            pm2(
"内部委托调用内部类的方法");
        }
    }
}


 

事件

由于MSDN含混不清的误导,很多人会认为:事件就是一种受限的委托。但实际上不是!
事件与委托的关系好比字段与属性的关系。
事件实际上是一种委托属性,只不过这个属性重载的不是赋值运算符,而是+=和-=运算符。

对于一个属性而言,对它的赋值和取值运算会被转换为两个方法的调用。
例如:obj.A 这个属性
obj.A = "aaa";       将调用 set 访问器:   set {  _a = value;  }
string a = obj.A;   将调用 get 访问器:   get {  return _a;  }

而事件也是一样,假设有一个事件obj.E,则下面的表达式也等同于后面的形式:
obj.E += d;              obj.add_E( d )
obj.E -= d;              obj.remove_E( d )


事件与属性的共同点:
事件也可以被继承;
事件也可以被重写;
事件也可以是虚的或者抽象的(表现在add和remove方法是抽象的或者虚的);

理论上,事件的add和remove方法也可以有不同的访问权限。


事件与属性的不同点:
属性是必须实现的,事件则不必(或者说,事件是最早出现的自动属性);

与自动属性一样,事件也会创建一个字段来保存对应的委托实例,而这个字段与事件同名且是私有。在C#中,你可以访问到这个字段,因为它真的就是一个字段。
换言之,在C#中写代码时,如果是在类的内部使用事件,其实就是引用那个自动生成的私有字段(委托字段)。
而在类的外部使用事件,是不同于在类的内部使用事件(因为这个字段是私有的,所以在类的外部也就访问不到)。

event 本质上所做的工作应该还是通过 delegate 来实现的,或者至少原理相同。event 关键字只不过是让CLR给所定义的 delegate 对象进行一个封装。
event 是通过对 delegate 的限制来封装一部分本来就不应该暴露在外的行为,从而更符合面向对象的思想(封装的原则)。


附加:
1、事件其实是由三个方法add、remove和raise组成的。但C#编译器总是不会生成raise方法。
2、自动事件不同的编译器实现是不同的,例如VB的编译器生成的私有字段是(事件名)Event。
3、Web开发中的Control也是事件驱动的。


参考来源:
http://www.cnblogs.com/Ivony/archive/2009/09/10/1563876.html
http://www.cnblogs.com/jujusharp/archive/2008/11/01/CSharp-delegate-event-difference.html

推荐阅读:[叩响C#之门]写给初学者:自定义事件

posted on 2010-04-28 20:30  钢钢  阅读(894)  评论(1编辑  收藏  举报

导航