一、代理

首先我们要弄清代理是个什么东西。别让一串翻译过来的概念把大家搞晕了头。
有的文章把代理称委托、代表等,其实它们是一个东西,英文表述都是“Delegate”。由于没有一本权威的书来规范这个概念,所以现在网上对它的称谓不一。本文我将以“代理”来称谓Delegate。
代理是什么呢?我认为“代理就是用来定义指向方法的引用”。下面我们就通过类来理解代理。
如:
Ren r = new Ren("车延禄");
上面的代码,就是使用Ren这个类定义了一个指“车延禄”这个对象实例的一个引用。
也可以这样理解:用Ren类定义的变量r,指向一个“车延禄”对象的实例。
类所定义的变量指向的是一个对象,代理所定义的变量指向的是个方法,当然这个方法可以是静态方法也可以是实例方法。对代理引用的调用就是对代理所指向方法的调用。
1.代理声明的语法:
[public/private] delegate <返回值类型> <代理名称>(<参数列表>);

[public/private]:访问修饰符。
delegate:代理声明关键定,相当于类声明的Class关键定
<返回值类型>:代理所指向的方法的返回值类型
<代理名称>:代理类型的名称
<参数列表>:代理所的指向的方法的参数列表。

要想使代理对象能够指向一个方法,那这个方法的要满足两个条件
a.方法返回类型要与delegate声明中的“返回值类型”一致。
b.方法的形参形表要与delegate声明中的“参数列表”一致。

如:
delegate void MyDelegate(string str,int index);
该代理声明表示:该代理指向的方法必须是返回空类型,并且拥有两个参数,第一个是字符串类型,第二个是整型。
2.代理“实例化”:
代理声明相当于类的定义。有了类的定义后我们要还需生成这个类的对象;同样有了代理的声明我们还需要“实例化”代理

如:MyDelegate md = new MyDelegate(Show);

这里的md就是代理变量。在代理的“实例化”的时候必须在构造函数中传入一个方法名。这个方法名就是该代理指向的方法,当然该方法的返回值类型与参数类型一定要与代理的声明一致。

Show方法定义如下:
public static void Show(string str, int index)
{
Console.WriteLine("Show"+str+index.ToString());
}
3.代理的调用:
md("hello world",22);
此时调用的就是md这个代理变量所指向的Show方法。
4.例子:
delegate void MyDelegate(string str,int index);    //声明代理
class Test
{
public static void Show(string str, int index)     //声明方法
{
Console.WriteLine("Show"+str+index.ToString());
}
public static void Main(string[] args)
{
MyDelegate md = new MyDelegate(Show); //1.实例化代理,传入方法
md("hello world",22);                                    //2.传入参数
}
}
5.代理的应用:
代理的主要应用就是在DotNet中的事件处理,所以要想研究事件我们必须要理解代理的概念。有的文章使用代理进行冒泡排序,我感觉这没必要,因为不用代理我也可以排序,更况且在C#语法中也不需要我们手动编写冒泡排序代码。
关于代理,大家要理解代理是个什么东西,并且能够写一个简单的代理示例就可以了。

二、多播代理
上面我们讲的代理是一个代理对象指向一个方法,在调用该代理对象的时候就会调用它所指向的方法。多播代理就是为一个代理挂接上多个方法,当执行该代理的时候就会依次执行该代理上挂接的方法。
1.多播代理的声明与上面讲得基本上一样:

[public/private] delegate void <代理名称>(<参数列表>);

只有一点不一样的就是,多播代理所指向的方法应当是void类型。
2.多播代理“实例化”
多播代理“实例化”与上面讲得一样,在此不多说了。

如:MyDelegate md = new MyDelegate(Show);

3.多播代理挂接多个方法。
多播代理可以使用 += 运算符挂接多个方法,也可以使用 -= 运算符从挂接列表中删除相应的挂接方法。

如:
delegate void MyDelegate(string str,int index);
class Test
{
public static void Show(string str, int index)
{
Console.WriteLine("Show"+str+index.ToString());
}
public static void TestInt(string str, int index)
{
Console.WriteLine("Testint");
}
public static void Main2(string[] args)
{
MyDelegate md = new MyDelegate(Show);  //传入方法
md += new MyDelegate(TestInt);                   //传入另一个方法
md("hello world",22);
}
}
在上面这个例子当中有两个方法(Show和TestInt)符合MyDelegate代理的签名,如果要把这两个方法挂接到我们一个代理变量上去的话,就得用 += 运算符了。
MyDelegate md = new MyDelegate(Show);
md += new MyDelegate(TestInt);
这里的md代理变量上先挂接了Show方法,再挂接TestInt方法。当执行md("hello world",22)的时候会先调用Show方法,再调用TestInt方法。
事件本身就是一种多播代理

三、事件:    1.用执行事件传入参数     2.用注册事件传入方法
C#中的事件就是代理的一个变量。它和属性、方法一样,都是类的成员。只不过事件是指向一个方法,当事件被触发时,就会执行对象的相关方法。
事件的这种对方法的引用并不是写死在代码里面的,而是可以进行更改的。辟如:我们在DotNet中按钮的OnClick事件,它可以指向符合OnClick事件签名的任何一个方法。
1.事件的定义使用event关键字:
public event CryHandler DuckCryEvent;

其中的CryHandler是一个delegate。从上面的代码我们可以看出来:事件就是一个代理类型的变量。
private delegate void CryHandler();
2.指定事件处理程序:
指定事件处理程序就是为事件挂接方法的过程。
DuckCryEvent +=new CryHandler(Cry);   //注册事件,传入方法
public void Cry()
{
Console.WriteLine("我是一只小鸭,呀依呀依呀....");
}

3.执行事件
执行事件就是调用事件所指向方法的过程。一般对事的执行代码写在相应的方法或属性中,如果方法或属性被调用时就触发事件。
public void BeShaked()
{
DuckCryEvent();
}

4.完整的例子:
//事件用到的代理,以般以×××Handler的格式进行命名
private delegate void CryHandler();             //无参代理
//玩具小鸭的类
class Duck
{
  //定义小鸭的唱歌事件
public event CryHandler DuckCryEvent;
public Duck()
{
  //把小鸭唱歌的事件挂接到Cry方法上
DuckCryEvent +=new CryHandler(Cry); //注册事件,传入方法
}
//小鸭唱歌事件对应的处理方法
public void Cry()
{
Console.WriteLine("我是一只小鸭,呀呀呀....");
}
//小鸭被摇动
public void BeShaked() //执行方法,引发cry事件
{

DuckCryEvent();                                  //执行事件,传入参数
}
}
class Class2
{
public static void Main3(string[] args)
{
  //买一只小鸭
Duck d = new Duck();
//摇一摇小鸭,它就会调触发小鸭的Cry事件,小鸭就会唱歌
d.BeShaked();
}
}
   四、注意事项

C#中的delegate和C++中的函数指针基本是一回事,C#正是以delegate的形式实现了函数指针。不同的地方在于C#中delegate是类型安全的并且完全面向对象的。

Delegate 与C++相比优点:

A、函数指针只能指向静态函数,而delegate既可以指向静态函数也可以指向非静态成员函数。

B、与函数指针相比,delegate 是面向对象、类型安全、可靠的受控对象,runtime 能够保证delegate 指向一个有效的方法,不须担心delegate指向无效地址或是越界地址。

要理解Delegate,首先,你要明白,它是一个类,他和Class是一个级别的概念,不同在于Class的定义包含字段和方法,而delegate只包含方法的细节。Delegate 类能够拥有一个签名(signature),并且它只能持有与他的签名相匹配的方法的引用。

(1)在C#中,所有的代理都是从System.Delegate类派生的(delegate是System.Delegate的别名)。

(2)代理隐含具有sealed属性,即不能用来派生新的类型。

(3)代理最大的作用就是为类的事件绑定事件处理程序。

(4)在通过代理调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。

(5)在代理实例中可以封装静态的方法也可以封装实例方法。

(6)在创建代理实例时,需要传递将要映射的方法或其他代理实例以指明代理将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。

(7)只有当两个代理实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。

(8)多个代理实例可以形成一个代理链,System.Delegate中定义了用来维护代理链的静态方法Combion,Remove,分别向代理链中添加代理实例和删除代理实例。

(9)代理三步曲:
           a.声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型:   delegate int MyDelegate();
           b.创建delegate对象,并将你想要传递的函数作为参数传入:

MyDelegate d = new MyDelegate(MyClass.MyMethod);
          c.在要实现异步调用的地方,通过上一步创建的对象来调用方法。using System;

int ret = d();

五、托管函数

1、什么是托管函数?

托管函数是一个对类里面的某个函数的一个引用。它子并没有具体的函数定义,只是指向某个函数实现。

2、托管函数有什么作用?

由于托管函数是对类里面某个函数的一个引用.所以我们不必知道这个函数的具体名字是什么,而只需要调用托管函数,让托管函数去调用相应的函数就可以了. 一个例子: 一个公司,一个领导,一个领导秘书,三个员工分别管理市场,策划和生产.这里秘书就相当与一个托管函数, 领导要下达什么命令(获得市场信息,生产什么产品),只需要对秘书说给我一份市场报告或者我们不生产原子弹转向生产氢弹.然后再由秘书根据领导的命令选择的去找哪个员工,再把员工获得的信息返回给领导. 这里面三个员工对于领导是透明的,领导并不知道自己下达的命令具体是由谁执行的.

示例: //给秘书下达命令执行

public void ExecuteCommand(string command)

{  switch(秘书根据命令判断是要给谁执行的)

{  // 这里的实现类似于某种设计模式

case 调研市场的人:

Doit=new Do(new MarketMan().GetMarketInfo);Break;

Case 生长产品的人:

Doit=new Do(new ProductMan().ProduceProduct);Break;

Default: Break;

}

}

 
 

C#代理多样性的更多相关文章

  1. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  2. nginx配置反向代理或跳转出现400问题处理记录

    午休完上班后,同事说测试站点访问接口出现400 Bad Request  Request Header Or Cookie Too Large提示,心想还好是测试服务器出现问题,影响不大,不过也赶紧上 ...

  3. Visual Studio Code 代理设置

    Visual Studio Code (简称 VS Code)是由微软研发的一款免费.开源的跨平台文本(代码)编辑器,在十多年的编程经历中,我使用过非常多的的代码编辑器(包括 IDE),例如 Fron ...

  4. DynamicObject - 代理对象的种类

    开箱即用,DynamicProxy提供了多种代理对象,主要分成两个大类: 基于继承(Inheritance-based) 基于继承的代理是通过继承一个代理类来实现,代理拦截对类的虚(virtual)成 ...

  5. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...

  6. 实现代理设置proxy

    用户在哪些情况下是需要设置网络代理呢? 1. 内网上不了外网,需要连接能上外网的内网电脑做代理,就能上外网:多个电脑共享上外网,就要用代理: 2.有些网页被封,通过国外的代理就能看到这被封的网站:3. ...

  7. 23种设计模式--代理模式-Proxy

    一.代理模式的介绍       代理模式我们脑袋里出现第一个词语就是代购,其实就是这样通过一个中间层这个中间成是属于什么都干什么都买得,俗称"百晓生",在平时得开发中我们经常会听到 ...

  8. 使用Java原生代理实现AOP

    ### 本文由博主柒.原创,转载请注明出处 ### 完整源码下载地址 [https://github.com/MatrixSeven/JavaAOP](https://github.com/Matri ...

  9. Javascript 代理模式模拟一个文件同步功能

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Android Intent Scheme URLs攻击

    0x0 引言 我们知道,在Android上的Intent-based攻击非常普遍.这样的攻击轻则导致应用程序崩溃.重则可能演变提权漏洞.当然,通过静态特征匹配,Intent-Based的恶意样本还是非 ...

  2. pip 安装

    pip安装 1.在以下地址下载最新的PIP安装文件:http://pypi.python.org/pypi/pip#downloads   2.下载pip-7.1.2.tar.gz (md5, pgp ...

  3. python标准库介绍——24 traceback 模块详解

    ==traceback 模块== [Example 2-18 #eg-2-18] 展示了 ``traceback`` 模块允许你在程序里打印异常的跟踪返回 (Traceback)信息, 类似未捕获异常 ...

  4. Gitbook 生成 pdf 中文字体错乱问题解决办法

    Gitbook 生成 pdf 中文字体错乱问题解决办法   用过 Gitbook 的都知道, Gitbook 会自动生成 pdf 以提供下载, 但十分遗憾的是自动生成的 pdf 对中文的支持并不好, ...

  5. 多主机共享ssh Public/Private Key

    前期服务器比较少,所有代码都放在github的私库中,在自己的github 设置中设置SSH keys就可以拉下相应的库中的代码到本地与服务器了,但是最近服务器多家了几台,每台都生成key加到gith ...

  6. cocos2dx 3.x designResolutionSize须主动设置

    cocos2dx 3.x最初设置screenSize和designResolutionSize的地方如下: bool AppDelegate::applicationDidFinishLaunchin ...

  7. Creating the Help Page in ASP.NET Web API

    Introduction In this article we will define the process of creating the help page in the ASP .NET We ...

  8. php的安装

    首先我们安装nginx #0.安装ningx(可选cd /disk1/toolsrpm -ivh  http://nginx.org/packages/centos/6/noarch/RPMS/ngi ...

  9. ps钢笔工具 (重要工具)

    ps钢笔工具 ctrl键 + 鼠标选中操作的点 = 移动点 alt键 + 方点 + 拖拉 = 拖出两个手柄 和 控制两端弧度 alt键 + 圆点 = 控制单向弧度

  10. HTML: < 和 > 是何方神圣

    懂HTML的,都知道 < 表示 <,> 表示 >,那还有什么好写呢? 知道是知道,记不记得住是另外一回事,今天用到这两家伙,又给忘记了,还要特意查了下. 缩写不好记,如果能知道 ...