C#学习5-委托与事件

来源:互联网 发布:淘宝买lol贵号 编辑:程序博客网 时间:2024/05/20 14:26

一、 什么是委托:

大家先看一个示例:

下面类中是两个函数,分别实现的二倍,和平方的功能

class MathsOperations

{

public static double MultiplyByTwo(double value)

{

return value*2;

}

public static double Square(double value)

{

return value*value;

}

}

在下面代码中,我们需要多次调用这两个函数(大家想以一下按以前的方法调用我们应该如何写代码)

using System;

namespace SimpleDelegate

{

delegate double DoubleOp(double x);

class MainEntryPoint

{

static void Main()

{

DoubleOp [] operations =

{

new DoubleOp(MathsOperations.MultiplyByTwo),

new DoubleOp(MathsOperations.Square)

};

for (int i=0 ; i<operations.Length ; i++)

{

Console.WriteLine(“Using operations[{0}]:”, i);

ProcessAndDisplayNumber(operations[i], 2.0);

ProcessAndDisplayNumber(operations[i], 7.94);

ProcessAndDisplayNumber(operations[i], 1.414);

Console.WriteLine();

}

}

static void ProcessAndDisplayNumber(DoubleOp action, double value)

{

double result = action(value);

Console.WriteLine(

Value is {0}, result of operation is {1}”, value, result);

}

 

下面是一个冒泡排序的函数

 

//void Boble(int[] sortArray) 可能不一定传入整型

for (int i = 0; i < sortArray.Length; i++)

{

for (int j = i + 1; j < sortArray.Length; j++)

{

if (sortArray[j] < sortArray[i]) // 比较的如果是自定义类型又如何?

{

int temp = sortArray[i]; // 交换的类型如果是其它类型?

sortArray[i] = sortArray[j];

sortArray[j] = temp;

}

}

}

 

看下面的代码,可以对所有类型的数据进行排序

class BubbleSorter

{

static public void Sort(object [] sortArray, CompareOp gtMethod)

{

for (int i=0 ; i<sortArray.Length ; i++)

{

for (int j=i+1 ; j<sortArray.Length ; j++)

{

if (gtMethod(sortArray[j], sortArray[i]))

{

object temp = sortArray[i];

sortArray[i] = sortArray[j];

sortArray[j] = temp;

}

}

}

}

}

 

定义自定义的类,完成员工按工资进行排序

class Employee

{

private string name;

private decimal salary;

public Employee(string name, decimal salary)

{

this.name = name;

this.salary = salary;

}

public override string ToString()

{

return string.Format(name + “, {0:C}”, salary);

}

public static bool RhsIsGreater(object lhs, object rhs)

{

Employee empLhs = (Employee) lhs;

Employee empRhs = (Employee) rhs;

return (empRhs.salary > empLhs.salary) ? true : false;

}

}

using System;

namespace Wrox.ProCSharp.AdvancedCSharp

{

delegate bool CompareOp(object lhs, object rhs);

class MainEntryPoint

{

static void Main()

{

Employee [] employees =

{

new Employee(“Bugs Bunny”, 20000),

new Employee(“Elmer Fudd”, 10000),

new Employee(“Daffy Duck”, 25000),

new Employee(“Wiley Coyote”, (decimal)1000000.38),

new Employee(“Foghorn Leghorn”, 23000),

new Employee(“RoadRunner’”, 50000)};

CompareOp employeeCompareOp = new CompareOp(Employee.RhsIsGreater);

BubbleSorter.Sort(employees, employeeCompareOp);

for (int i=0 ; i<employees.Length ; i++)

Console.WriteLine(employees[i].ToString());

}

}

如果我们要排序的产品的大小(以库存或价格排序),又如何实现

关于对象排序,还有没有其它方法

可能的答案:重载比较操作符

 

必须成对重载

public static bool operator == (Employee e1, Employee e2)

{

if (e1.salary==e2.salary)

return true;

else

return false;

}

public static bool operator != (Employee e1, Employee e2)

{

if (e1.salary!=e2.salary)

return true;

else

return false;

}

public static bool operator < (Employee e1, Employee e2)

{

if (e1.salary<e2.salary)

return true;

else

return false;

}

public static bool operator > (Employee e1, Employee e2)

{

if (e1.salary>e2.salary)

return true;

else

return false;

}

小结:

委托是对相同参数和返回值的函数,可以交给一个对象支统一调用,可以重用代码

 

二、 多次委托:

DoubleOp operations = new DoubleOp(MathOperations.MultiplyByTwo);

operations += new DoubleOp(MathOperations.Square);

 

DoubleOp operation1 = new DoubleOp(MathOperations.MultiplyByTwo);

DoubleOp operation2 = new DoubleOp(MathOperations.Square);

DoubleOp operations = operation1 + operation2;

 

执行:Operations(3)

 

结果是什么?

分别调用了二倍和平方算法

小结:这样可以多次给委托对象赋值,然后一次输出

 

三、 事件

C#中的事件机制是通过委托来实现的

我们看一个例子:以上面的员工类为例

class Employee

{

private string name;

private decimal salary;

public Employee(string name, decimal salary)

{

this.name = name;

this.salary = salary;

}

public override string ToString()

{

return string.Format(name + “, {0:C}”, salary);

}

public void save()

{

     //code1

     Console.WriteLine(name+”is saved”);

}

}

 

当我们希望在保存前能提示用户输入的信息时我们怎么做,我们在code1处加上一段代码

Console.WriteLine(“now is Saving data!,please wait”);

这样虽然可以,但这个类编译以后,代码就定死了不好改动了,如能在客户端给出回调代码则是较好的设计。

 

Using System;

Public delegate void EventHandle();  //1

 

class Employee

{

//略

 

public event EventHandle beforeSave; //2

 

public void save()  

{

     //code1

     if(beforeSave!=null)

          beforeSave();      //4

     Console.WriteLine(name+”is saved”);

}

}

 

class Demo

{

     public static void Main()

     {

          Employee emp = new Employee(“”,”ddd”);

          Emp.beforeSave+=new EventHandle(MyBeforeSave);   //5

          Emp.save();

     }

     static void MyBeforeSave()   //6

     {

          Console.WriteLine(“now is Saving.wait please”);

     }

}

 

事件:

1.  定义一个公共委托方法Public delegate void EventHandle();

2.  在组件中用委托声明事件public event EventHandle beforeSave;

3.  增加事件注册和移除的方法   //可不用

4.  在要调用的方法前后加上委托的方法调用public void save()

5.  在客户端注册事件Emp.beforeSave+=new EventHandle(MyBeforeSave);

6.  在客户端写被委托的方法内容static void MyBeforeSave()

 

客户工程代码如下:

using System;

using System.Collections.Generic;

using System.Text;

 

namespace DelegateDemo

{

    class Program

    {

     public static void Main()

     {

          Employee emp = new Employee("gobn",new Decimal(123.34));

          emp.beforeSave+=new EnventHandle(MyBeforeSave);   //5

          emp.save();

        Console.ReadLine();

     }

     static void MyBeforeSave()   //6

     {

          Console.WriteLine("now is Saving.wait please");

     }

 

    }

}

 

 

Employee类如下

using System;

using System.Collections.Generic;

using System.Text;

 

namespace DelegateDemo

{

    public delegate void EnventHandle();

    class Employee

    {

        private string name;

        private decimal salary;

        public Employee(string name, decimal salary)

        {

            this.name = name;

            this.salary = salary;

        }

        public event EnventHandle beforeSave; //2

 

        public void save()  

        {

             //code1

             if(beforeSave!=null)

                 beforeSave();      //4

             Console.WriteLine(name+" is saved");

        }

 

    }

}