惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Jina AI
Jina AI
P
Palo Alto Networks Blog
GbyAI
GbyAI
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
Hugging Face - Blog
Hugging Face - Blog
小众软件
小众软件
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
Blog — PlanetScale
Blog — PlanetScale
S
Schneier on Security
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
雷峰网
雷峰网
T
Tenable Blog
人人都是产品经理
人人都是产品经理
T
Tor Project blog
C
Cyber Attacks, Cyber Crime and Cyber Security
AWS News Blog
AWS News Blog
Microsoft Security Blog
Microsoft Security Blog
J
Java Code Geeks
Scott Helme
Scott Helme
SecWiki News
SecWiki News
C
CERT Recently Published Vulnerability Notes
Recorded Future
Recorded Future
I
InfoQ
Security Archives - TechRepublic
Security Archives - TechRepublic
Help Net Security
Help Net Security
Cloudbric
Cloudbric
C
Check Point Blog
Engineering at Meta
Engineering at Meta
TaoSecurity Blog
TaoSecurity Blog
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
N
News and Events Feed by Topic
云风的 BLOG
云风的 BLOG
MyScale Blog
MyScale Blog
腾讯CDC
量子位
Application and Cybersecurity Blog
Application and Cybersecurity Blog
K
Kaspersky official blog
Vercel News
Vercel News
F
Full Disclosure
T
Troy Hunt's Blog
Forbes - Security
Forbes - Security
S
Security @ Cisco Blogs

博客园 - 文野

DDD自问自答 数据结构(C#语言版)——栈和队列 数据结构(C#语言版)——线性表 2011一月的三个故事 我想要的2011 我的2011的三个故事 《悟透JavaScript》中的知识点 用Windows Live Writer写博客 我们是不是把MVC、ORM等技术的主次颠倒了? 论单一职责 对象结构 由做梦想到的 2009第一帖,测试用Word2007发布博客 一点一点学ASP.NET之基础概念——事件 应用框架的设计与实现学习手札系列(持续更新) 未解决的问题(持续更新) 应用框架的设计与实现学习手札之类工厂服务——反射 一点一点学ASP.NET之示例——HttpModule 示例 一点一点学ASP.NET系列(持续更新)
一点一点学ASP.NET之基础概念——委托
文野 · 2006-08-11 · via 博客园 - 文野

委托

—— 一点一点学ASP.NET

文野:2006811星期五


上一篇:一点一点学ASP.NET之基础概念——HttpHandler

委托的概念

委托实际上是类(一个貌似函数一样的类),我们已经使用函数指针很多年了——函数指针也被称为过程类型,但是它们的实现都不是类。它们是单独的函数指针的简单实例。委托是包含这些功能的类,委托类通过保留的列表来确定某些事物是否已经指派给了委托,这种算法可以理解为:“对于内部列表中的每一个回调函数,都调用函数”。委托除了支持回调函数外,还可以通过该列表来实现多播(委托链)。

说白了,就是我们把一批具有相同特征的方法,通过建立与具有同样相同特征的委托的一个实例来进行传递,以使其它地方能对这些方法进行调用。即把方法当作参数进行传递(浅显的认识,勿笑)。

初识委托

示例1

using System;

using System.Collections.Generic;

using System.Text;

using System.Web;

namespace MyDelegateTest

{

     /// <summary>

     /// 说明:一个简单的委托示例

     /// 作者:文野

     /// 联系:stwyhm.cnblogs.com

     /// </summary>

     // 新建一个用以输出消息的委托

     public delegate void WriteMessage();

     public class WriteToWeb

     {

         // 一个输出消息的静态方法

         public static void StaticWrite()

         {

              HttpContext.Current.Response.Write("委托调用了一个静态方法。<br />");

         }

         // 一个输出消息的类实例方法

         public void Write()

         {

              HttpContext.Current.Response.Write("委托调用了一个类实例方法。<br />");

         }

     }

}

调用:

protected void Page_Load(object sender, EventArgs e)

    {

         // 新建一个委托,回调函数是一个静态方法

         WriteMessage wm = new WriteMessage(WriteToWeb.StaticWrite);

         WriteToWeb w = new WriteToWeb();

         // 新建一个委托并与加到先前建立的委托组成委托链,回调函数是一个类实例方法

         wm += new WriteMessage(w.Write);

         // 执行委托链上所有的回调函数

         wm();

    }

 

上面的示例程序首先建立了一个简单得不能再简单的用以输出的委托,下面的类中有两个与委托签名一致的方法(一个静态方法,一个类实例方法)。下面的调用过程首先建立了一个使用回调静态方法的委托,其后又建立了一个使用类实例方法的委托并与先前的委托组成了一个委托链,最后执行委托链上所有的方法。

由此可见,委托最简单的理解就是利用与方法签名一致的委托,可以把方法当作参数一样来传递,无论是静态方法还是类实例方法。

委托的秘密

从上面的类视图中我们看到,对委托的定义最终被编译成一个类,这个类中定义有4种方法:构造器,InvokeBeginInvokeEndInvoke

所有的委托都继承自MulticastDelegate,而MulticastDelegate又继续至Delegate。这样我们定义的委托自然也就继承了MulticastDelegate的字段、属性和方法。在继承得到的所有成员中,有3个最重要的字段:

1_target:指向调用回调函数时应该操作的对象。该字段用于实例方法的回调。

2_methodPtr:一个内部的整数值,CLR用它来识别回调的方法。

3_prev:指向另一个委托对象。

当编译器知道我们在构造的是一个委托时,它会分析源代码来确定要引用哪个对象和方法。其中对象引用会被传递给_target(对于静态方法,_target被置为null),一个特殊的标识方法的Int32值会被传递给_methodPtr_prev在构造器中被置为null,它被用于在委托链中记录下一个委托的引用。

每个委托对象实际上是对方法及其调用操作的一个包装,MulticastDelegate中定义了两个只读属性,TargetMethodTarget(其实就是前面的_target字段)属性返回一个方法回调时操作的对象的引用,Method属性返回一个标识回调方法的System.Reflection.MethodInfo对象。

委托链

前面介绍过MulticastDelegate中有一个_prev的私有字段,这个字段指向另一个MulticastDelegate对象的引用,这样就实现了委托链(其实与我们在学链表时的实现方式是一致的)。

当委托链表被调用时,它首先会调用委托中在其前面的委托对象,这里如果被调的回调方法具有返回值,将被丢失,委托链只会返回最后一次调用回调方法的返回值。

委托示例

这是一个我自认为比较经典的委托示例(给排序算法传递一个动态比较的函数)。

using System;

using System.Collections.Generic;

using System.Text;

namespace MyDelegateTest

{

     /// <summary>

     /// 说明:给排序算法传递一个动态比较函数的委托示例

     /// 作者:文野

     /// 联系:stwyhm.cnblogs.com

     /// </summary>

     // 进行排序的委托

     public delegate bool Compare(int left, int right);

     public class DelegateSample

     {

         private int[] items;

         public int[] Items

         {

              set { items = value; }

              get { return items; }

         }

         // 比大

         public bool Greater(int left, int right)

         {

              return left > right;

         }

         // 比小

         public bool Less(int left, int right)

         {

              return !Greater(left, right);

         }

         public void Sort(Compare compare)

         {

              for (int i = 0; i < items.Length-1; i++)

              {

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

                   {

                       if (compare(items[i], items[j]))

                       {

                            int tmp = items[i];

                            items[i] = items[j];

                            items[j] = tmp;

                       }

                   }

              }

         }

     }

}

调用页面

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using MyDelegateTest;

public partial class Sort : System.Web.UI.Page

{

     protected void Page_Load(object sender, EventArgs e)

     {

     }

     protected void Button1_Click(object sender, EventArgs e)

     {

         DelegateSample sample = new DelegateSample();

         sample.Items = GetItems();

         // 使用降序

         sample.Sort(new Compare(sample.Less));

         PrintItems(sample);

     }

     private void PrintItems(DelegateSample sample)

     {

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

         {

              Response.Write(sample.Items[i] + "<br/>");

         }

     }

     private int[] GetItems()

     {

         string[] str = this.TextBox1.Text.Split(",".ToCharArray());

         int[] items = new int[str.Length];

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

              items[i] = int.Parse(str[i]);

         return items;

     }

     protected void Button2_Click(object sender, EventArgs e)

     {

         DelegateSample sample = new DelegateSample();

         sample.Items = GetItems();

         // 使用升序

         sample.Sort(new Compare(sample.Greater));

         PrintItems(sample);

     }

}

效果图:

降序

升序


 

参考资料:

.NET框架程序设计》

Visual Basic .Net Power Coding

本文源码:

下载

 
下一篇:一点一点学ASP.NET之基础概念——事件