从事件来看委托

事件是基于委托,为委托提供了一种发布/订阅机制,在dotNet到处都能看到事件,一个简单的例子就是在windows应用程序中,Button类提供了Click事件,这类事件就是委托,触发Click事件时调用的处理程序方法需要定义,其参数也是由委托类型定义的,事件模型可以用下图简要说明。

在这个模型中,事件的响应者通过订阅关系直接关联在事件拥有者的事件上,我们把这种事件模型或者CLR事件模型。因为CLR事件本质上是一个委托实例,我们暂且模仿CLR属性的说法,把CLR事件定义为一个委托类型实例的包装器。

下面一个示例,事件用于连接CarDealer类和Consumer类,CarDealer类提供了一个新车到达时的触发事件,Consumer类订阅该事件,以获得新车到达的通知。从CarDealer类开始,它基于事件提供一个订阅,CarDealer类用event关键字定义了类型为EventHandler<CarInfoEventArgs>的NewCarInfo事件,在NewCar()中,通过调用RaiseNewCarInfo方法触发NewCarInfo事件,这个方法的实现检查委托是否为空,如果不为空,就引发事件。

 public class CarInfoEventArgs : EventArgs
    {
        public string Car { get; private set; }
        public CarInfoEventArgs(string car)
        {
            this.Car = car;
        }
    }

    public class CarDealer
    {
        public event EventHandler<CarInfoEventArgs> NewCarInfo;
        public void NewCar(string car)
        {
            Console.WriteLine("CarDealer,new car {0}", car);
            RaiseNewCarInfo(car);
        }

        protected virtual void RaiseNewCarInfo(string car)
        {
            NewCarInfo?.Invoke(this, new CarInfoEventArgs(car));
        }
    }

Consumer类用作事件侦听器,这个类订阅了CarDealer类的事件,并定义了NewCarIsHere方法,该方法满足EeventHandler<CarInfoEventArgs>委托的要求,其参数类型是object和CarInfoEventArgs.

 public class Consumer
    {
        private string name;
        public Consumer(string name)
        {
            this.name = name;
        }
        public void NewCarIsHere(object sender, CarInfoEventArgs e)
        {
            Console.WriteLine($"{name}:car {e.Car} is new");
        }
    }

需要连接事件发布程序和订阅器,为此使用CarDealer类的NewCarInfo事件,通过“+=”创建一个订阅,然后通过“-=”取消订阅

 var dealer = new CarDealer();
            var myCar = new Consumer("MyCar");
            dealer.NewCarInfo += myCar.NewCarIsHere;
            dealer.NewCar("OneCar");
            dealer.NewCarInfo -= myCar.NewCarIsHere;
            dealer.NewCar("OtherCar");

通过事件,直接连接到发布程序和侦听器,但垃圾回收器有个问题,如果侦听器不在直接引用,发布程序就仍有一个引用,垃圾回收器不能清空侦听器占用的内存,因为发布程序仍有一个引用,会针对侦听器触发事件,这种强连接的模式可以通过弱引用事件模式来解决,即使用WeakEventManager作为发布程序和侦听器之间的中介。

更改Consumer的代码实现IWeakEventListener接口

public class Consumer : IWeakEventListener
    {
        private string name;

        public Consumer(string name)
        {
            this.name = name;
        }

        public void NewCarIsHere(object sender, CarInfoEventArgs e)
        {
            Console.WriteLine("{0}: car {1} is new", name, e.Car);
        }

        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            NewCarIsHere(sender, e as CarInfoEventArgs);
            return true;
        }
    }

更改订阅事件的代码

 var dealer = new CarDealer();
            var myCar = new Consumer("MyCar");
            WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", myCar.NewCarIsHere);

            //dealer.NewCarInfo += myCar.NewCarIsHere;
            dealer.NewCar("OneCar");
            WeakEventManager<CarDealer, CarInfoEventArgs>.RemoveHandler(dealer, "NewCarInfo", myCar.NewCarIsHere);
            //dealer.NewCarInfo -= myCar.NewCarIsHere;
            dealer.NewCar("OtherCar");

WPF使用弱事件模式和事件管理器,在dotNet中委托是类型安全的类,它定义了返回类型和类型参数的类型,委托不仅半酣方法的引用,也可以包含对多个方法引用,lambda表达式与委托直接相关,当参数是委托类型时,就可以直接使用lambda表达式实现委托引用的方法,除了为每个参数和返回类型定义一个新委托之外,还可以使用Action<T>和Func<T>委托,泛型Action<T>委托表示引用一个void返回类型的方法,Func<T>允许调用带返回类型的方法,下面用委托实现经典的冒泡排序,定义一个实体类,在类中定义一个返回bool类型的静态方法,定义一个实现排序方法的BubbleSorter类

Employee[] employees =
            {
            new Employee("Bugs Bunny", 20000),
            new Employee("Elmer Fudd", 10000),
            new Employee("Daffy Duck", 25000),
            new Employee("Wile Coyote", 1000000.38m),
            new Employee("Foghorn Leghorn", 23000),
            new Employee("RoadRunner", 50000)
            };
            BubbleSorter.Sort(employees, Employee.CompareSalary);
            foreach (var employee in employees)
            {
                Console.WriteLine(employee);
            }

 public class BubbleSorter
    {
        static public void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison)
        {
            bool swapped = true;
            do
            {
                swapped = false;
                for (int i = 0; i < sortArray.Count - 1; i++)
                {
                    if (comparison(sortArray[i + 1], sortArray[i]))
                    {
                        T temp = sortArray[i];
                        sortArray[i] = sortArray[i + 1];
                        sortArray[i + 1] = temp;
                        swapped = true;
                    }
                }
            } while (swapped);
        }
    }
    public class Employee
    {
        public Employee(string name, decimal salary)
        {
            this.Name = name;
            this.Salary = salary;
        }

        public string Name { get; private set; }
        public decimal Salary { get; private set; }

        public override string ToString()
        {
            return string.Format("{0}, {1:C}", Name, Salary);
        }

        public static bool CompareSalary(Employee e1, Employee e2)
        {
            return e1.Salary < e2.Salary;
        }
    }

实际上,定义一个委托是指定义一个新类,委托实现为派生自基类的System.MulticastDelegate的类,System.MulticastDelegate又派生自基类System.Delegate,C#编译器会识别这个类,并使用其委托语法。

时间: 2024-12-23 18:32:23

从事件来看委托的相关文章

事件与委托

C# 中的委托和事件 文中代码在VS2005下通过,由于VS2003(.Net Framework 1.1)不支持隐式的委托变量,所以如果在一个接受委托类型的位置直接赋予方法名,在VS2003下会报错,解决办法是显式的创建一个委托类型的实例(委托变量).例如:委托类型 委托实例 = new 委托类型(方法名); 引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易

C#事件与委托详解【精华 多看看】

Delegate delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类.与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与它的签名相匹配的方法的引用".它所实现的功能与C/C++中的函数指针十分相似.它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m.但与函数指针相比,delegate有许多函数委托和事件在 .Net Framework中的应用非常广泛指针不具备的优点.首先,函数指针只能指

C#基础知识之事件和委托

本文中,我将通过两个范例由浅入深地讲述什么是委托.为什么要使用委托.事件的由来..Net Framework中的委托和事件.委托和事件对Observer设计模式的意义,对它们的中间代码也做了讨论. 委托的引入:将方法作为方法的参数 我们先不管这个标题如何的绕口,也不管委托究竟是个什么东西,来看下面这两个最简单的方法,它们不过是在屏幕上输出一句问候的话语: public void GreetPeople(string name) { EnglishGreeting(name); } public

C# 事件和委托

1 public class Heater { 2 private int temperature; 3 public string type = "RealFire 001"; // 添加型号作为演示 4 public string area = "China Xian"; // 添加产地作为演示 5 //声明委托 6 public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e)

[C#参考]事件和委托的关系

前面说了委托,接下来就要说一说事件了,同时最后再说一下委托和事件的区别. 事件和委托很相似,事件就好像是被简化的针对特殊用途的委托.看下面的图: 结合前面说的委托的知识,事件的组件应该是这个样子的: 看到发布者必须有触发事件的代码,也就是必须为事件的调用留有接口,不能直接调用事件(不要觉得事件是委托类型的).这里要强调的是事件是成员,是发布者的一个成员,它不是类型,它的类型是委托类型的. 虽然事件是委托类型的,但是事件对委托做了一次封装,并且事件封装的委托是private的,所以是不能从发布者外

C# 事件与委托的区别

C# 事件与委托的区别 先看一段程序 class Program { static void Main(string[] args) { Test obj = new Test(); obj.print += printout1; //绑定printout1方法 obj.print += printout2; //绑定printout2方法 obj.start(); } static void printout1() { Console.WriteLine("输出第一段字符串"); }

事件和委托

委托:对方法的绑定 事件和委托的步骤1.定义委托public delegate 返回值 委托名(参数);2.基于委托定义事件public event 委托名 事件名; 3.注册事件对象.事件名 += new 委托(方法); 4.触发事件 先检查事件是否有人注册,有则触发 if (事件名 != null) 事件名(); 事件和委托,布布扣,bubuko.com

事件与委托更新父窗体数据,简单比较

1.委托更新父窗页面. 例如,功能:父窗体A,子窗体B,由A打开B窗体,更新A窗体数据 A窗体代码: public delegate void reflshPassenger();//声明委托 private void btnAddPassenger_Click(object sender, EventArgs e)//打开B窗体按钮,并把委托窗体给B窗体        {            reflshPassenger reflshData = getPassengers;       

面向对象基础——事件和委托

事件和委托 在典型的面向对象软件的一般流程中,代码段创建类的对象并在该对象上调用力法.在这种情况下,调用程序是主动代码,因为它们是调用方法的代码.而对象是被动的,因为只有当某种方法被调用时才会用上对象并执行某种动作. 然而,也可能存在相反的情况.对象可以执行一些任务并在执行过程中发生某些事情时通知调用程序.称这类事情为事件(event),对象的事件发布称为引发事件. 事件驱动处理对于.NET来说并不是什么技术,在事件驱动处理中,当有事件发生时,某些代码段会通知其他对事件感兴趣的代码段.当用户使用