怎样理解C#中的委托代理机制
很多书和文章都希望能够从原理层面把代理机制讲清楚,从C和C++的指针讲到线程安全,从通用类库讲到事件驱动,对于高端玩家,这是很有必要的,但对于初学者,就容易越看越晕,从云山雾罩,到云深不知处,本来只有一个概念不懂,现在变成N个了,最后只能投降,不了了之。
这个概念确实不太容易理解。下面尝试根据我的理解来说明。
我们在开发期间最常用的方法所传递的参数,一般情况下是某个类型的变量,比如:
public long op(long a,long b) { return a + b; }
现在我给你出个题,你帮我向方法A中传递一个方法B,并在A中执行B。
是不是不会了?
对部分开发者来讲,这确实是一个新的概念,或者说是一个新的操作方式,以前没这样做过。
聪明的你可能已经想到了,对,在C#中,此时要用到代理。
按照方法签名的定义方式,要传递的参数应该是“某个类型 形参”,比如上例中的long a。那么要传递的这个方法的“类型”是什么呢?
就是代理,delegate。
当你要向一个方法A传递另一个方法B的时候,要为这个B方法单独定义一个“类型”,它要求的有三个要素,参数类型、个数、返回值,只要符合这三项的,都可以传。
比如要向方法A传递上例中的op(long a,long b)方法,就要像下面这样定义:
public delegate long TwoLongsOp(long a, long b);
这时,一个新的“类型”就产生了,所有符合“两个long型参数、返回值为long”特点的方法,都符合这个类型定义。
现在就可以解答我上面出的题了,使用这个类型向方法A传递方法B。
首先要有方法A:
public long Atest(TwoLongsOp a) { return 0; }
显而易见,这个方法什么也没做,但它可以传一个代理了,离成功近了一点儿。
下一步开始调用传过来的参数a,要注意,这个参数是个带有两个参数和返回值的方法,调用它也就是执行它。
怎么调用呢?
就像在方法A中调用其它方法一样。
public long Atest(TwoLongsOp a) { var r = a(2,3); return r; }
到这里,程序是可以编译的,符合编译规则,但没什么用。因为我们还没有定义方法B,也就是方法A的那个“实参”。
下面我们来定义方法B,方法B一定要符合delegate所定义的格式,参数、返回值,一定要一致:
public long Btest(long a,long b) { //其实这里写点什么都行,不一定非得是对a和b的操作,只是对入参进行操作是对它们最大的尊重。 return a + b; }
接下来就可以正式调用了,当当当当~~向方法A中传入方法B:
public ActionResult Index() { ViewBag.Message = Atest(Btest).ToString(); return View(); }
我们再定义一个C:
public long Ctest(long a, long b) { return a * b; }
接下来可以这样调用:
public ActionResult Index() { ViewBag.Message1 = Atest(Btest).ToString(); ViewBag.Message2 = Atest(Ctest).ToString(); return View(); }
有一点思考一下,代理与方法B和方法C,到底是B和C被代理限制,还是代理为B和C服务?
想必有人会问,这样操作的意义是什么,直接调用Btest不就可以了?
对,在本例中,是的。但在很多团队合作的情况下,A不是你写的,甚至不是你们公司写的,暴露给你的只是一个方法名,要求传入符合方法签名要求的方法。或者你是写A的人,要给写B的人留下余量。
“委托”或者“代理”一词应该怎样理解呢?
从方法的角度来讲,对于参数,它只认识“类型 参数”的模式,所以,方法的“类型”是什么呢?它没有内置的类型,所以无法直接传递。既然不能直接向A传递B,就需要一个“中间人”,定义一个新的“类型”,A和B委托deleate定义的那个东西作为媒介,把B传给A。这个新定义的类型,服从A和B的约定(参数类型、个数、返回值)。所以,委托的定义是为A、B、C服务,它们有需求,所以需要一个合格的中间人。
有些事情只能是在开发过程中遇到了才会意识到它的作用和价值,在遇到之前,不太容易理解。本例权当是一次智力游戏。
念念不忘,必有回响,诚不我欺,共勉。
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击