几个.NET方面的问题——参考答案

几个.NET方面的问题中,列出了几个.NET方面的问题,但是没有给出问题的答案,因为对于一部分问题我自己也不是很确定。这次只是给出一个参考答案,仅仅作为参考。如有不对的地方,欢迎大家指正。

 

1.       为什么要显式地关闭StreamWriter

这个问题可以从《框架设计》P409找到答案,书上用了专门的一节解释了这个问题。简单来说,因为StreamWriter在调用Write方法向Stream写入数据之后,数据还可能是在StreamWriter的缓冲区中。如果不显式关闭StreamWriter,那么数据能否真正写入Stream中,就要取决于.NETGC先回收Stream还是先回收StreamWriter。如果GC先回收了Stream,那么在回收StreamWriter时,StreamWriter会试图把缓冲区中的数据写入到一个已经关闭的Stream中,从而发生异常。

2.       如何正确地重写GetHashCode方法?

这个问题可以从《框架设计》P123找到答案,也是用了专门一节讲述这个问题。一个正确的GetHashCode方法要满足下面的要求:

1.       Equals方法行为一致。如果a等于b,则aHash应该也等于bHash

2.       Hash值有良好的分布

3.       满足生存期的值稳定性。

4.       最好要快速。

这么多要求,如果没有写过可能还真一时不好下手,其实只要把与Equals方法相关的字段的Hash值异或起来就可以了。

3.       C#编译器为什么要用callvirt指令调用实例的非虚方法?

这个问题也是来源于《框架设计》,作者也很惊讶为什么会这样,不过他只告诉我们这样没有问题,却没有说为什么要这样。P139里的“重要提示”,写到如果一个方法从非虚改成虚方法,如果非虚方法是用call调用,那么这个更改会造成虚方法被非虚地调用,产生不可知的后果。所以干脆都用callvirt好了。

我看了一下callvirtcall的区别,除了方法调用逻辑有一定不同,callvirt还会检查变量是否为NULL,而call不会。其实call根本就不能检查,它还要调用静态方法呢,检查谁去?而实例方法,一般是要使用实例字段的,这就要求实例不能为null,所以用callvirt顺便检查一下。(其实书中也是想这么解释的,不过书印错了。见下面勘误。)

所以估计是上面两个原因,让C#团队选择了callvirt。好处多多。

PS:《框架设计》勘误:P139L3,“call”应该是“callvirt”。

4.       Struct可以继承吗?为什么?可以有虚方法吗?为什么?

不可以继承,因为C#语法不允许。(我实在不想这么回答,但是也实在找不出为什么。)

也不可以有虚方法,都不能继承,虚个屁。

5.       什么时候用const,什么时候用static readonly

所有书上都会告诉你const是编译时常量,readonly是运行时常量。

但是什么时候用呢?比如你想限制你的程序可以运行的实例的个数为5,用哪个好像都可以哦,不过最好用static readonly,因为哪天你可以把这个数改成6。只要你能改的,就用static readonly,而不要用const。什么时候用const?表示MaxInt, PI, e光速等等数学常量,亘古不变的量,才用const。重申一下,个人观点,仅供参考。至于为什么,可以参考这篇文章

6.       C#为什么要提供析构函数?

一个原因是为了用于方便地释放本地资源(就是非托管资源)。大家补充。^_^

7.       有时,程序的Debug Build可以正常运行,而Release Build不能。可能是什么原因?

我一想到这个问题的时候,感觉无从下手。天知道为什么!谁知道代码怎么写能写出这么恶心的BUG出来。其实细想想,同样的代码,Debug Build可以运行,而Release Build不能运行。只可能是编译器生产的代码不同。只要知道debug buildrelease build有什么不同,这个问题也就解决了。至于总共有多少不同点,可真是不好说。《框架设计》P387专门用了一节讲了一个不同——变量的生存期不同。Debug build为了方便调试,“将所有变量的生存期扩展到方法结束”。而release build中,编译器就不会做这样的事情,这样一个变量就有可能被过早地当作垃圾回收掉了。这就有可能导致debug build可以正常运行,而release build不能。具体解释可以参考《框架设计》。

这是个开放式的问题,应该不止这一种情况。欢迎大家补充。

 

 

 

另外又想到了几个问题:

1.       我们都知道短小的方法,有可能在编译时被编译器内联处理。那么在什么情况下,我们会希望阻止一个方法在编译时被内联?

2.       C#中,有几种方式可以防止一个方法在编译时被内联?

 

 

posted on 2009-04-18 16:59  南柯之石  阅读(630)  评论(1编辑  收藏  举报

导航