從事件來看委託

事件是基於委託,爲委託提供了一種發佈/訂閱機制,在dotNet處處都能看到事件,一個簡單的例子就是在windows應用程序中,Button類提供了Click事件,這類事件就是委託,觸發Click事件時調用的處理程序方法須要定義,其參數也是由委託類型定義的,事件模型能夠用下圖簡要說明。windows

在這個模型中,事件的響應者經過訂閱關係直接關聯在事件擁有者的事件上,咱們把這種事件模型或者CLR事件模型。由於CLR事件本質上是一個委託實例,咱們暫且模仿CLR屬性的說法,把CLR事件定義爲一個委託類型實例的包裝器。安全

下面一個示例,事件用於鏈接CarDealer類和Consumer類,CarDealer類提供了一個新車到達時的觸發事件,Consumer類訂閱該事件,以得到新車到達的通知。從CarDealer類開始,它基於事件提供一個訂閱,CarDealer類用event關鍵字定義了類型爲EventHandler<CarInfoEventArgs>的NewCarInfo事件,在NewCar()中,經過調用RaiseNewCarInfo方法觸發NewCarInfo事件,這個方法的實現檢查委託是否爲空,若是不爲空,就引起事件。app

 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.ide

 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事件,經過「+=」建立一個訂閱,而後經過「-=」取消訂閱this

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

經過事件,直接鏈接到發佈程序和偵聽器,但垃圾回收器有個問題,若是偵聽器不在直接引用,發佈程序就仍有一個引用,垃圾回收器不能清空偵聽器佔用的內存,由於發佈程序仍有一個引用,會針對偵聽器觸發事件,這種強鏈接的模式能夠經過弱引用事件模式來解決,即便用WeakEventManager做爲發佈程序和偵聽器之間的中介。spa

更改Consumer的代碼實現IWeakEventListener接口code

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;
        }
    }

更改訂閱事件的代碼orm

 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類blog

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#編譯器會識別這個類,並使用其委託語法。排序

相關文章
相關標籤/搜索