对C#中委托和事件的理解

这段时间在学习C#委托的概念,首先借用网上的一个例子来引出委托是什么。我们都知道在调用方法的时候是采用这种形式public void Function(String str1,int number) ,这里的function是方法名,str、number是要传入的参数,这种结构的函数能满足一些简单的需求,但是假如现在有一个排序的方法

 public void Sort(int[] array)
        {
            for (int i = 0; i < array.Length; i++)
            {
                bool swaped = false;
                do
                {
                    if (array[i] > array[i + 1])
                    {
                        int temp = array[i];
                        array[i] = array[i + 1];
                        array[i + 1] = temp;
                        swaped = true;
                    }

                } while (swaped);
            }
        }

这个方法是对传入的数组用冒泡排序法进行排序,但是他只能对整数进行处理,那么如果现在要对string类型的数组进行排序,那么array[i] > array[i + 1]这个判断肯定不能成立,于是就想到了一个办法就是将array[i] > array[i + 1]这个作为一个方法传入函数体内,那便可以大大的增加这个排序方法的复用性能,继续附上代码:

 public void CommonSort(IList<T> array,Comparison compare)
        {
            for (int i = 0; i < array.Count; i++)
            {
                bool swaped = false;
                do
                {
                    if (compare(array[i],array[i+1]))
                    {
                        T temp = array[i];
                        array[i] = array[i + 1];
                        array[i + 1] = temp;
                        swaped = true;
                    }

                } while (swaped);
            }
        }

其中comparison类型的定义是

        public delegate bool Comparison(T value1,T value2);

它就是一个委托,委托其实就是一个对方法的引用,学过C++的人就可以把它理解成为是指向方法的指针,只不过委托只能指向已定义好类型的方法,是类型安全的,它这里只能指向方法签名是这个格式的 bool Comparison(T value1,T value2); 

既然生命好了方法的委托,必然要实例化一个委托,并且将具体的方法绑定给它(就相当于将指针指向具体的方法)所以需要定义一个方法。

这样函数就能像其它string,int参数一样传入方法体了,但是它和别的参数不同的地方在于它是可以绑定多个方法的,也就是称之为多播委托。接下来举个例子:

  class Program
    {
        public delegate void delegateGreet(string name);
        static void Main(string[] args)
        {
            string name = "jerry";
            delegateGreet dg1 = new delegateGreet(ChineseGreet);
            dg1 += EnglishGreet;
            dg1(name);
            Console.ReadKey();
        }
        public static void ChineseGreet(string name)
        {
            Console.WriteLine("你好,{0}", name);
        }
        public static void EnglishGreet(string name)
        {
            Console.WriteLine("morning,{0}", name);
        }
    }

这里 public delegate void delegateGreet(string name);首先签名了一个委托,限制了委托能绑定方法的类型,是一个返回为空,传入参数为string的委托类型。接着delegateGreet dg1 = new delegateGreet(ChineseGreet);  实例化了一个这个委托类型。然后将两个满足 void delegateGreet(string name);类型的方法分别绑定到这个实例上,也就是dg1中保存了一个指向两个函数的指针链。接着通过dg1(name)调用它,则它会分别依次调用这两个绑定的函数。

显示结果为


接着引入事件的概念 首先来看事件的声明方式

public delegate void delegateGreet(string name);
public event delegateGreet myevent;
可以很容易发现声明事件其实就是在实例化之前定义的委托类型,所以它就是封装一个了特定类型的委托实例。个人觉得事件的实现就是依靠多播委托的特性,来依次执行绑定的方法(但是这个方法是规定类型的)。接下来举一个Observer模式的例子来说明事件的作用

public class Heater
    {
        public event EventHandler<BoilEventArgs> Boil;
        private int tempature;
        //public event BoilEventHandler Boil;
        public void BoilWater()
        {
            for (int i = 0; i <= 100; i++)
            {
                tempature = i;
                if (tempature>95)
                {
                    OnBoil(tempature);
                }
            }
        }
        public void OnBoil(int temp)
        {
            BoilEventArgs e=new BoilEventArgs(temp);
            Boil(this, e);
        }

    }

class Displayer
    {
        public void Display(object sender,BoilEventArgs e)
        {
            Console.WriteLine("现在温度是{0}℃", e.tempature);
        }
    }

class Alerter
    {
        public void Alert(object sender,BoilEventArgs e)
        {
            Console.WriteLine("滴滴滴滴滴滴谁开啦 温度是{0}℃",e.tempature);
        }
    }

public class BoilEventArgs:EventArgs
    {
        public readonly int tempature;
        public BoilEventArgs(int tempat)
        {
            tempature=tempat;
        }
    }

这里需要注意的是
正如前面所说的,这里的事件应该这样定义

public delegate void BoilEventHandler(object sender,BoilEventArgs e)  ;
public event BoilEventHandler Boil;
这样定义是肯定没错的,但是假如我们需要其它的事件处理方法类型,那么我们就得重写BoilEventHandler,这种做法在.net1.0中是这样做的,但是随着泛型的引入我们可以这样定义事件处理方法类型
public event EventHandler<BoilEventArgs> Boil;
这里的EventHandler<TEventArgs>,其实应该写成这样EventHanler(object sender,TEventArgs e),之所以用TEventArgs这个类型传递参数是为了规范化事件处理方法的类型,试想,假如我们一个事件处理函数需要传入100个参数,那么这个方法会很难看,所以.net引入的EventArgs,即事件参数,我们可以通过继承EventArgs将事件发布者需要传出的参数都定义在这个类中,这样代码就优雅了很多。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值