发表评论
#1楼 [
楼主]2007-11-14 08:25 |
@Yucj
是热水器的第一种实现,还是问候的第一种实现,我没在vs2003下调试,编译器报得什么错呢? 把错误信息发上来好么
#3楼 [
楼主]2007-11-14 13:29 |
@lv_Sally
WPF 还没有学习过···
博主,首先感谢你的回复。
我说的编译有错,就是第一段最简单的那个早上好的例子,在VS2003下报
GreetPeople("Jimmy Zhang", EnglishGreeting); 错误:方法EnglishGreeting没有带参数
66楼的朋友也提到了。
我在2005下试没问题,但是2003下就不行。因为没用过2005,工作中用2003,所以不太了解其中的奥秘。
#5楼 [
楼主]2007-11-14 19:17 |
@Yucj
我没有装Vs2003,所以没调试,但我估计是因为2003下不允许这样隐式的传递方法变量,必须显式地把它实例化成委托变量。
当直接写 GreetPeople("Jimmy Zhang", EnglishGreeting); 的时候,编译器不认为 EnglisghGreeting 是一个委托变量,而把当它成是一个普通的方法进行处理。此时 GreetPeople 方法认为它的第二个参数是 EnglishGreeting 的返回值。而 EnglishGreeting 这个方法的调用格式不对,它没有参数,于是告诉你:该方法没有参数。
如果想成功,我想是要这样写,你可以试一下:
GreetPeople("Jimmy Zhang", new GreetingDelegate(EnglishGreeting));
非常感谢Jimmy,GreetPeople("Jimmy Zhang", new GreetingDelegate(EnglishGreeting)); 已经解决了编译出错的问题了。继续拜读你的大作了,哈哈。
Hi Jimmy or net C# developers:
How C# project or solution deal with Garbage Collection case. Do we have to design garbage case by our self or VS 2005 auto clean.
Can you point out to very detail : How garbage come out and when we have to face to deal with it. Thanks!
#12楼 [
楼主]2007-11-20 08:35 |
@强总是我
最近很忙,有时间了会考虑
感谢回复。。文章不错我喜欢。。会常来的。。@张子阳.
#15楼 [
楼主]2007-11-21 14:48 |
@Lisa Tian
I am sorry that I do not know much about garbage collection, so I am not sure about the question you asked.
楼上那位说英语的朋友,你是不是闲心太多,竟操用不着的心.回收机制由framework自己管,绝大多数情况下不用我们操心的!!!!
@张子阳.
Thanks for the feedback. Me too. But I be asked the question in job interview time. I feel hard to answer it. I will check Google also.
@jack2
Thanks Jack2. It is very good answer to regular case. But some case may need to work on it in application. sorry I do not have Chinese word software in my pc yet.
Happy Thanksgivig to all C# Developers in here.
楼主写的很好,还提供PDF版下载,中国就缺乏这样的好人才,有些人也许是大师级的人物了,这篇文章帮不了你,你也没必要出口不逊,毕竟你没有像楼主这样为菜鸟的技术进步作出了贡献!
写的很好.我学C#最难的就是在委托\事件这里.看了明白了很多.谢谢!
楼主再多谢点好东东,很多初学者很需要,包括在官方上都找不到澄清一些概念.你真是我们初学福音啊!
看了这个文章后,我还是没明白为什么要使用委托
比如你提的问候的问题,很明显各种语言的问候方法你都写了,那我在调用的时候直接调用不行了,你在使用委托的时候不还是需要把各个方法对应的绑定到委托变量中去,我能找到他们作对应,就不能找到他们直接调用?
如果楼主能找个合适例子回答我这个问题,我万分感激!!!
Best article about introducing delegate and event I have ever read.
For somebody whose foot just cross the door, really really excellent.
namespace myTreeView
{
class TreeView : System.Windows.Forms.TreeView
{
......
public System.Windows.Forms.TreeView Tv_Tree;
......
public bool UpdateTree()
{
TreeNode RootNode = new TreeNode();
......
Tv_Tree.Nodes.Add(RootNode);
}
}
}
我有这么一个自定义组件,但是在外部程序绑定 ImageList 的时候,节点图片显示不了,我觉得是 ImageList 没绑定到 Tv_Tree 上,但是不知道该怎么做,在此请教各位热心的朋友.
文章后面部分写得不是很详细,这编文章很适合初学者,在继续EventArgs类上能否再深入点呢?还有事件和委托连的相似地方可以稍微的切入讲下吗?给我感觉事件本身就是一个委托链,去掉Event之后就成了委托链的声明了
以前只简单应用过.Net FrameWork中的委托 对事件的应用不是很明白 重读了一遍楼主的文章 感觉深入多了
有一篇“组件和控件开发”是你写的吗 那个也不错 再详细些或做个实例供下载就好了
写得非常好,搞了几天没有明白委托和事件的意思,看了博主的文章后受益非浅,希望能写出更好的文章给初学者!
#35楼 [
楼主]2007-12-02 19:45 |
@史向平
如果在执行各个语言版本的问候之前需要都进行一系列的其他操作呢?这些操作对每个问候方法都是相同的,难道在每个语言版本的方法中把这些操作重写一遍么?就算你这么做了,如果现在要求这些公共操作每月都会有更新,你要全部重写一遍么?
你可能没看清我代码注释里的说明:
public void GreetPeople(string name, Language lang){
//做某些额外的事情,比如初始化之类,此处略 <-- 请注意这里
swith(lang){
case Language.English:
EnglishGreeting(name);
break;
case Language.Chinese:
ChineseGreeting(name);
break;
}
}
在 GreetPeople 中可以执行一些对于每个具体的问候方法都存在的额外的操作。
另外,委托并不是只有注册这种使用方式或者说功能,声明好一个委托后,你可以直接将符合此委托声明的方法当作委托类型的变量来传递到另一个方法当中!
#36楼 [
楼主]2007-12-02 20:12 |
@哎呀姐姐
个人觉得前面部分写详细些,理解了以后,后半部分是前面的一个应用和深入,不用太细致应该就能明白,所以就没有做太多文字说明,直接写到代码注释了。
EventArgs 是对于订阅者(Observer端)所感兴趣的数据进行的一个封装。可以这么想,当写某个方法时,需要给它传递若干个参数(个数不定),这样方法的声明就会很麻烦,你可能要写三个参数,或者5个,或者更多,但是如果你把这些参数封装到一个对象中,传递参数的时候,传递这个对象,那么你只需要一个参数就可以了。
你完全可以不继承EventArgs来实现这个功能,但是继承它更加符合.Net的规范。
实际上,热水器例子的委托类型完全可以不用声明,而使用.Net Framework 已经提供的声明,这个声明在System命名空间下面:
public delegate void EventHandler (Object sender,EventArgs e)
声明事件的时候,也只要这样写就可以了:public event EventHandler Boiled;
事件是对委托变量的封装,本质上并没有什么太大区别,只是使得对委托的使用更方便一些,所以你的理解并不错。
#37楼 [
楼主]2007-12-02 20:13 |
@闭上眼睛想谁-
你说的那个控件和组件开发的文章不是我写的 :-)
其实.net的委托和event可以完全用接口来实现.
JAVA就是这么弄的。
不知道两种不同的实现会不会有什么区别?
我是初学者,当初为了学C#,选了很多书都不合适,最后确定用清华的《微软技术丛书--Visual C# 2005 从入门到精通》做为我的入门教材,这本书总的来说还是比较受看的(至少于我如是,言语分析得很浅显易懂),但真如子阳兄所说的“较好地理解委托和事件对很多接触C#时间不长的人来说并不容易”,我把书上的“委托与事件”那章翻来覆去看了又看,真觉得“biè”得慌,索性又跑到书城去把C#的书翻来看,站着看累了又蹲着看,蹲累了又站起来看......结果,我果然很笨,只把委托弄明白了点;无奈只好在网络上需求帮助,从百度上搜索到了子阳兄的这篇文章,看了过后虽不能说是茅塞顿开,但文章思路非常清晰,还回答了我一直盘旋的问题“既然有委托了,拿事件来有何用?”我现在看了一遍,开始变得有信心继续学习下去了,我将这篇文章打印出来订成一本,闲暇时反复再看几遍,相信一定能过这道槛儿。
再次感谢楼主。
品君文章一篇,胜我读书十本.
不过有一点不明:
heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
这句用意何在?
望楼主给于解答.
再次感谢!
#42楼 [
楼主]2007-12-04 18:18 |
@Ling Yue
这个没有什么特别的用意,和其他的一样,只是演示一下委托的多种注册方式。
#43楼 [
楼主]2007-12-04 18:20 |
@luna
呵呵,对你有所帮助就好,你的学习精神也让我佩服~~~
hao.......
留言的人几乎都说好,其实真的很好。支持。对我帮助很大。
@ahshow
I am sure that you are very smart to understand OO and C#. But for 80% of new C# developer. Jimmy offer the information. It is very help us to enter the C# developer door.
看了两篇,感觉上面的委托部分还可以, 可是到了下面的事件就不是太懂了.
不过还是非常感谢jimmy,,
楼主:你的文章写得很好,深入浅出,有点老外讲技术的风格。我已经保存了,并且会在一个.net community的presentation中讲这个主题,会用到你的文章。翻译成英文是可行的,如果需要帮助,可以email给我,我会把我的英文ppt发给你。
#52楼 [
楼主]2007-12-10 20:17 |
@Amy Cheng
谢谢!如有需要我会联系您。
老兄,太谢谢你啦!
我这几天被这个委托的事搞的头都大啦,看了你的文章,让我茅舍顿开,你是个优秀的老师,再次谢谢你,我会收藏你的博客地址,也希望你能接受我这个菜鸟朋友!
#54楼 [
楼主]2007-12-11 18:19 |
@liwuman
呵呵,当然,来这里的我都视作是我的朋友 :-)
感谢楼主张老师! vs2003没有using System.Collections.Generic;
谢谢楼主了,太好了,让我这刚学C#不久的人也会用委托和事件了
但是下面这段代码还是不太明白为什么要这样,为什么不把这几句直接写在方法里?
// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBolied(BoliedEventArgs e) {
if (Boiled != null) { // 如果有对象注册
Boiled(this, e); // 调用所有注册对象的方法
}
}
#57楼 [
楼主]2007-12-12 19:56 |
@初始小花
这样是为了方便让继承自Heater的子类拒绝其他对象监视的能力,同时又不影响其本身的行为(BoilWater)。OnBoiled方法实际上是把 调用外部类注册的方法 的过程单独取出来了。这样我们如果在子类中不希望有其他类对它的BoilWater采取反应,那么只要简单的覆盖OnBoiled方法就可以了。如果我们想继续让子类保持被监视的能力,只需要在子类方法中加上base.OnBoiled(e)。(如果你做Asp.Net,观察一下就会发现.Net Framework就是采用这种方式)
It is the best article about C# delegate and event i once read through website.
You are so generous and kind to spend spare time for c# developer.
Wish you all the best
既然事件是在类中声明的,并且是声明为类的一个private字段,那么我们在定义这个类的变量后为什么可以直接访问这个变量的事件字段啊?
就以楼主前面的代码为例:事件MakeGreet是类GreetingManager的private字段,那么在类GreetingManager的外面应该是不能访问gm.MakeGreet 的,但语句gm.MakeGreet += ChineseGreeting;却是合法的,这不是矛盾吗?
请楼主为我解惑,不胜感激!!!!!!
#62楼 [
楼主]2007-12-18 13:22 |
@江流石不转
请你仔细看下文章,我里面写得很清楚了。
MakeGreet事件确实是一个GreetingDelegate类型的委托,只不过不管是不是声明为public,它总是被声明为private。另外,它还有两个方法,分别是add_MakeGreet和remove_MakeGreet,这两个方法分别用于注册委托类型的方法和取消注册。实际上也就是: “+= ”对应 add_MakeGreet,“-=”对应remove_MakeGreet。而这两个方法的访问限制取决于声明事件时的访问限制符。
多谢楼主,你的文章写的很好,我看得也很仔细,但我还是不太明白。
即便add_MakeGreet与remove_MakeGreet都是public方法,这也只是说明这两个方法对类的用户来说是可见的,在类的的外部可以调用这两个方法,而类的非公有成员对用户来说始终是不可见的。(楼主,这几句话应该没有说错吧?)
语句gm.MakeGreet += ChineseGreeting;明显是用户所写(而且是合法的),并且出现了成员MakeGreet,这就表明了类GreetingManager的成员MakeGreet对用户来说是可见的(虽然用户对这个成员的操作受到了一定的限制)。而实际上MakeGreet 是类MakeGreet的private成员,既然是private成员,那么对类GreetingManager的用户来说应该是不可见的,这两方面明显的矛盾了,烦请楼主为我耐心解答是怎么回事。
也许编译器对语句gm.MakeGreet += ChineseGreeting;这种情况看成是例外,从而对事件作特别对待,不用完全遵循类的一般成员的访问规则,请问楼主,是我说的这样吗?
#65楼 [
楼主]2007-12-19 08:48 |
@江流石不转
请你看一下代码语句public event GreetingDelegate MakeGreet; 所生成的中间代码:
private GreetingDelegate MakeGreet; //对事件的声明 实际是 声明一个私有的委托变量
//同时产生两个方法
public void add_MakeGreet(GreetingDelegate value){
this.MakeGreet = (GreetingDelegate) Delegate.Combine(this.MakeGreet, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_MakeGreet(GreetingDelegate value){
this.MakeGreet = (GreetingDelegate) Delegate.Remove(this.MakeGreet, value);
}
从编译器的角度来看,add_MakeGreet() 方法和 MakeGreet变量 没有什么必然的联系,为什么对add_MakeGreet() 方法的访问要受 MakeGreet 变量的限制呢? 而从程序员的角度来看,“=”视为对MakeGreet的赋值操作,显然是不允许的;而“+=”则视为对add_MakeGreet()方法的调用。
就类似于下面这样:
private string MakeGreet;
publice void add_MakeGreet(string value){
this.MakeGreet = value;
}
public void remove_MakeGreet(){
this.MakeGreet = "";
}
对add_MakeGreet() 方法的访问当然不受MakeGreet 变量的限制,但是对用户来说,要调用这个方法,必须通过类的private成员MakeGreet才能办到,从而也就把类的private成员暴露在了用户面前,虽然用户对这个成员的操作只能被限制在允许的范围内,但还是有违“类的非public成员对类的用户来说是不可见的”这个原则。
多谢楼主解说!!!
楼主的意思我也明白,声明MakeGreet时所用的访问限制符其实是用来限制方法add_MakeGreet() 与remove_MakeGreet()的。所以我只能这样理解:实质上gm.MakeGreet += ChineseGreeting;只是用户调用对象gm的方法add_MakeGreet() 的格式,而参数就是gm.MakeGreet += 右边的方法名ChineseGreeting。若是声明MakeGreet时访问限制符改为protected或是private,那gm.MakeGreet += ChineseGreeting;与gm.MakeGreet -= ChineseGreeting;其实就是用户调用了类的非public方法,当然会出错。语句gm.MakeGreet += ChineseGreeting;的意义对用户来说是很好理解的,但是我对编译器的这种做法还是感到很是别扭(在这个调用格式中有类的实质上的private成员).
c#中委托事件,线程,还有那关于流的问题不是很懂得,要认真向你们学习,博主啊,再写些好帖子,我肯定来光顾的哦,呵呵呵。
看一遍不行,明天来第二遍,我还就不信了呢
第一次看这个文章,,感觉不是很懂的..稀里糊涂的.
今天又看了一次这个文章,,对委托和事件有了深刻的认识.只要肯下功夫...就一定能学好的.......楼主的例子非常不错..但我不知道为什么要用委托和事件喃....?
我也是看到事件部分有点糊涂
对事件不是很了解
比较不错,谢谢楼主深入浅出的讲解
#73楼 [
楼主]2007-12-22 14:34 |
@踏雪寻梅2
多实践、多练习,慢慢就好了,只看书看文章是很难完全明白的。
写的深入浅出,我听了两遍都没懂,这次懂了,可是事件还是不明白,得仔细揣摩一下,谢谢搂主,希望搂主能介绍一下西安的牛人,这样我这样的菜鸟就不会孤立无助了
#75楼 [
楼主]2007-12-23 13:09 |
@绿色原野
西安的牛人我也不认识几个,大多都是线上交流,与是不是在西安关系不大。
事件不明白没有关系,多练练多用用慢慢就好了~~~
我以前以为能用委托实现的功能我不用照样能够实现
现在看来,我的经验还真是不够!~!~!!
写得真不错,希望能和楼主交个朋友,因为我是从java转过来的,一直对这几个问题不明白,终于弄清楚多了
msn: mefly@tom.com
你写的东西就是我想要找的东西.
但出现在很让我郁闷的事情,就是把你的代码搞下来却不能运行.不知道是哪里出了问题
using System.Collections.Generic; //这里出错说缺少程序集引用
gm.GreetPeople("Jimmy Zhang", EnglishGreeting);
gm.GreetPeople("张子阳", ChineseGreeting); //这里说在不加()的时候调用了函数,我把 "()"加上又说没有传入参数...
到底是程序的问题还是我自己的问题呢,希望你能给我说一下
#83楼 [
楼主]2008-01-01 15:12 |
@学习ASP.NETC#中
你用的是 Vs2003 吧。
对于问题1:注释掉 using System.Collections.Generic; 这一行。
对于问题2:请参看第 96 楼。
高手。。你呆哪个单微。。? 你对.net 理解挺深啊。。!! 佩服。。
写的真是不错,我也来顶一下!!!!以后多写写这样的文章哦~~
今天刚学习委托和事件,但是看了这篇文章有以下疑问
引用作者的话:
我们先看看如果把 delegate1 声明为 private会怎样?结果就是:这简直就是在搞笑。因为声明委托的目的就是为了把它暴露在类的客户端进行方法的注册,你把它声明为private了,客户端对它根本就不可见,那它还有什么用?
再看看把delegate1 声明为 public 会怎样?结果就是:在客户端可以对它进行随意的赋值等操作,严重破坏对象的封装性。
于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
第一.如果BoilEvent在类中总是private,为什么对Heater继承,一样会把BoilEvent继承过去;
第二.而BoilHandler 修饰符的访问性不能低于BoilEvent,那么BoilEvent如何被封装? BoilHandler 如果为private,BoilEvent也必须为private.BoilEvent在类外也无法使用。
前半部分构思很好,后半部分讲Observer我觉得可以做一个单独的文章,毕竟两者重叠的不多.
#93楼 [
楼主]2008-01-25 15:49 |