首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

委托

Posted on 2009-03-10 11:56  停留的风  阅读(4389)  评论(48编辑  收藏  举报

  委托可能是C#最难理解的概念之一,但是由于其担当的重任以及在编程中的广泛应用,我们不得不,认真去研究。如何才能够掌握委托的概念、理解其精华所在呢?我之前学的时候也比较晕,看着看着就把自己给搞糊涂了,有的时候心烦的就彻底放弃了。当然认识委托每个人的方法不一样,每个人的感触也不一样。现在谈谈我自己的感受,希望能给大家一些帮助。只是个人见解,可能不恰当,希望诸位仁兄批评指正。
  我们之前使用过抽象类、接口中的抽象方法。这个对于我们来说,非常的熟悉。父类声明一种方法,由子类继承实现。而子类的方法,可以将子类的实例转化为父类的实例进行调用,在后面的接口实例中就有这样的实现,你可以看一下。我们可以这样认为,抛开子类、父类,我们就可以说是方法的继承。就像下面例子中的,Perimeter中的ExecuteResult方法继承了接口InterfaceSm的ExecuteResult方法,InterfaceSm中的ExecuteResult就称为父方法,而Perimeter中的ExecuteResult则成为子方法。

Interface Code

 

  委托是一种引用方法的类型。与委托的签名匹配(具有相同的参数和返回值)的任何方法都可以分配给该委托。

  委托和接口都允许类设计器分离类型声明和实现。给定的接口可由任何类或结构继承和实现;可以为任何类中的方法创建委托,前提是该方法符合委托的方法签名。接口引用或委托可由不了解实现该接口或委托方法的类的对象使用。

  在委托中,我们也可以认为:

  委托是任何与委托的签名匹配的方法的父亲,所有与委托签名匹配的方法统称为该委托的子方法

  就像下面实例所示,ExecuteResult就是所有的与 int MethodName(int x, int y)匹配的方法的父方法,而getPerimeter和getArea则是ExecuteResult的子方法。  

using System;

namespace DelegateSo
{
    
class Program
    {
        
/// <summary>
        
/// 委托声明
        
/// </summary>
        public delegate int ExecuteResult(int x, int y);
        
/// <summary>
        
/// 计算矩形周长
        
/// </summary>
        
/// <param name="x"></param>
        
/// <param name="y"></param>
        
/// <returns></returns>
        public static int getPerimeter(int x, int y)
        {
            
return 2 * (x + y);
        }
        
/// <summary>
        
/// 计算矩形面积
        
/// </summary>
        
/// <param name="x"></param>
        
/// <param name="y"></param>
        
/// <returns></returns>
        public static int getArea(int x, int y)
        {
            
return x * y;
        }
        
/// <summary>
        
/// main
        
/// </summary>
        
/// <param name="args"></param>
        static void Main(string[] args)
        {
            
int x = 5, y = 10;
            ExecuteResult per 
= getPerimeter;
            ExecuteResult area 
= getArea;


            Console.WriteLine(
"The area of the rectangle is {0}.", area(x, y));

            ExecuteResult[] events 
={ getPerimeter, getArea };
            
for (int i = 0; i < events.Length; i++)
            {
                Console.WriteLine(
"The Result of Execute is {0}.", events[i](x, y));
            }

            
//Output
            
//The area of the rectangle is 50.
            
//The Result of Execute is 30.
            
//The Result of Execute is 50.
        }
    }
}

 

  现在应该对委托有个大概了解了,那么我们再继续研究Delegate。

  委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值.与委托的签名(由返回类型和参数组成)匹配的任何方法都可以分配给该委托。这样就可以通过编程方式来更改方法调用,还可以向现有类中插入新代码。只要知道委托的签名,便可以分配自己的委托方法。将方法作为参数进行引用的能力使委托成为定义回调方法的理想选择。例如,可以向排序算法传递对比较两个对象的方法的引用。分离比较代码使得可以采用更通用的方式编写算法。

委托的声明:

  委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似。与 C 中的函数指针不同,委托是面向对象的、类型安全的和保险的。委托的类型由委托的名称定义。如下例中所示。与委托的签名(由返回类型和参数组成)匹配的任何方法都可以分配给该委托。方法可以是静态方法,也可以是实例方法,例子中没有体现出来。 

 public delegate int ExecuteResult(int x, int y);

 

public static int getPerimeter(int x, int y){}

 

public static int getArea(int x, int y){}

 

 委托的特点:

  1、委托类似于 C++ 函数指针,但它是类型安全的

  2、委托允许将方法作为参数进行传递。

  3、委托可用于定义回调方法。

  4、委托可以链接在一起;例如,可以对一个事件调用多个方法。

  5、方法不需要与委托签名精确匹配。有关更多信息,请参见协变和逆变。

  6、C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。

常用的方法:

  1、合并委托(多路广播委托)

  委托对象的一个用途在于,可以使用 + 运算符将它们分配给一个要成为多路广播委托的委托实例。组合的委托可调用组成它的那两个委托。只有相同类型的委托才可以组合。- 运算符可用来从组合的委托移除组件委托。感觉就像做小学数学一样,简单、快捷。

在上述Main方法中加入如下代码:

            //加,如果有返回值,则返回最后一个执行函数的返回值
            ExecuteResult operates = per + area;
            Console.WriteLine(
"The Result of Execute is {0}.", operates(x, y));
            
//Output
            
//The Result of Execute is 50.

            
//
            ExecuteResult operate_del = operates - area;
            Console.WriteLine(
"The Per result is {0}.", operate_del(x, y));
            
//Output
            
//The Per result is 30.

 

  2、GetInvocationList返回委托的调用列表 

GetInvocationList()
            //得到委托中的方法总数
            int count = operates.GetInvocationList().GetLength(0);//operates = per + area;
            Console.WriteLine("{0}", count);
            
//遍历委托中所有的方法
            foreach (ExecuteResult item in operates.GetInvocationList())
            {
                Console.WriteLine(
"The Result is {0}.", item(x, y));
            }
            
//Output
            
//2
            
//The Result is 30.
            
//The Result is 50.

 

常见的委托实例

  1、定时执行,TimerCallback 

[ComVisible(true)]
public delegate void TimerCallback(object state);

 

Timer iTimer = new Timer(new TimerCallback(Doing));//定时执行
iTimer.Change(TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(1));

public void Doing(Object nObject){}

  2、自定义控件

WebControl Code

 

  3、EventHandler定义,可以通过Reflector看到

[Serializable, ComVisible(true)]
public delegate void EventHandler(object sender, EventArgs e);

 

  4、按钮事件

  按钮页面

<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"/>

  CodeBehind事件

protected void Button1_Click(object sender, EventArgs e) {}

  Click定义:

[WebCategory("Action"), WebSysDescription("Button_OnClick")]
public event EventHandler Click
{
    add
    {
        
base.Events.AddHandler(EventClick, value);
    }
    remove
    {
        
base.Events.RemoveHandler(EventClick, value);
    }
}

  Button类的OnClick定义

protected virtual void OnClick(EventArgs e);
protected virtual void OnClick(EventArgs e)
{
    EventHandler handler 
= (EventHandler) base.Events[EventClick];
    
if (handler != null)
    {
        handler(
this, e);
    }
}

 

何时使用委托而不使用接口,请参看

http://msdn.microsoft.com/zh-cn/library/ms173173(VS.80).aspx