天使

星期天回到父母家,晚上吃饭的时候不知怎么父亲想起萌萌一个事,说她聪明”不好糊弄了“,说捡来的故事不相信了。

萌萌这时候接了一句”我是从妈妈肚子里生出来的“样子颇为认真,让我感觉非常有意思,于是想逗逗她。

”你不是妈妈肚子里生出来的,是从天上来的天使”。

萌萌开始很怀疑,“我就是妈妈肚子里生出来的”,于是我把故事说的比较像回事“你是从天上飞下来的,我和你妈妈把你的翅膀都保存起来了,放在银行里“。

萌萌开始围绕这个问题不停地问“那我安上翅膀会不会飞?能不能把翅膀让我看看?我不信我就是妈妈肚子里生出来的“诸如此类,小脸兴奋地通红。

说着说着,突然冒出一句”爸爸是从白菜叶子里出来的,爸爸是菜青虫!“把我们笑到不行。

宝贝,你就是我们的天使啊!

2011-04-24_16-00-05_157

C#研究系列-List<>与ArrayList的几个研究心得及问题(下)

代码在这里:

https://gist.github.com/921385

与(上)一样在一开始定义了两个继承List与ArrayList的空类。
// public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable

class CFromList : List<int> { }

// public class ArrayList : IList, ICollection, IEnumerable, ICloneable

class CFromArrayList : ArrayList{ }

注意在87行,我注释了这行代码

// list1[index++] = a;

意思很简单,就是要修改iterate当前位置的值。
其实我当初写下这个代码也就是随手为之,因为这种行为在C++中不算啥(只是对值进行修改,并不会修改list本身内存排列)。
可是debug的时候,蹦出异常InvalidOperationException了。太奇怪了。
好在我设置了step into CLR code,所以能跟踪到List内部的一些实现。从73到85行就是我找到的一些内容。
在List.cs代码中,前面list1[index++]=a;的赋值语句会进入这个函数public T this[int index] set{},在这个属性函数中
_items[index] = value; _version++;
所以_version会增加1。在MoveNext函数中,会检查这个_version
private bool MoveNextRare() {

if (version != list._version) {

ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);

}

index = list._size + 1;

current = default(T);

return false;

}

很显然,赋值以后,version和list._version不一样了。如果我们用try catch包围这些代码,那么就会捕获这个异常。

另外一个问题来了,为何ArrayList没有异常呢?在我debug的时候,如果有list2[index++]=a;这样的修改,代码就挂在这块了,也没有异常弹出。

加上try catch以后就没有问题了,这个就更奇怪了。

从MSDN可以看到,List在foreach这种形式的循环下是不可以修改内容。必须说,这个规定太蛋疼了。如果想修改也很容易,不用这种iterator形式就好了。

Re 浅谈C和C++中的const关键字

This article contains many errors, I just list them simply.
http://www.cnblogs.com/dolphin0520/archive/2011/04/18/2020248.html

BTW About const concept in C/C++, I have 2 articles.
《c专家编程》阅读笔记-关于const指针 http://sunxiunan.com/?p=1161
技术笔记-关于c/c++中的const http://sunxiunan.com/?p=870

————————
“但是程序中使用过多的const,可能在对代码的阅读时增加一定的难度”
Can’t understand. This idea is so strange.
If possible, you should use const as possible. It is a good contract.

————————
const int n; 这种声明方式是错误的
This definition method is wrong. (should NOT declaration!)
extern char* const p; // this is declaration, p as extern variable

————————
指针常量:即指针本身的值是不可改变的,而指针指向的变量的值是可以改变的;
I never heard the concept “指针常量”, it should be “the pointer points to constant” 指针指向常量!!

————————
“C语言和C++中的const有很大区别。在C语言中用const修饰的变量仍然是一个变量;而在C++中用const修饰过后,就变成常量了。
const int a=3; int *pa=&a; *pa=4; printf(“%d\n”,*pa); printf(“%d\n”,a);
这种情况在C++中是不允许的,原因在于a用const修饰后,已经成为常量了,因此是不允许被修改的,无论是显示的更改a的值或是通过其它方法修改它的值都是不允许的。”

!!!! WTF !!
C++ has a keyword const_cast !!

Try following code:
const int a=3;
int *pa= const_cast < int * > (&a); *pa=4;
printf(“%d\n”,*pa);
printf(“%d\n”,a);

Will print out “4 4” as result.

C#研究系列-List<>与ArrayList的几个研究心得及问题(上)

代码放在gist.github.com上了,看不到的请留言。

第一个心得,是我看某本书提到,IList用起来要比ArrayList快。

这里面用到了我上一篇博客提到的高精度计时器 http://sunxiunan.com/?p=1829

我在开始定义了两个类。
// public class List : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable
class CFromList : List{}

// public class ArrayList : IList, ICollection, IEnumerable, ICloneable
class CFromArrayList : ArrayList{}
List和ArrayList的定义在注释中给出,可以看出来其实都差不多。ArrayList只是多了ICloneable,还少了几个泛型接口继承。

在后面代码中都用Add方法向list中添加int类型数据,然后通过foreach形式枚举数据,注意!枚举部分的代码是有问题的,我们在(下)中会提到。

这里还要推荐一个非常棒的工具ILSpy,是sharpdevelop开发的,强烈建议dotnet程序员都下载使用。

我把ILSpy disassemble出来的C#代码和IL代码分别列在后面。注意对于ArrayList的foreach语句,C#形式的代码与源代码有些差别(79到96行),编译器加入一个IEnumerator enumerator2 = cFromArrayList.GetEnumerator();本地变量,另外使用int num5 = (int)enumerator2.Current;这样访问iterator。而且还加入了IDisposable的finally部分。

再继续看IL代码部分,对于List形式,IL代码没有box装箱指令,而ArrayList在145行有个box指令,这是性能差别之一。
但是奇怪的是,在枚举部分,ILSpy生成的(以及ILDasm)IL代码,对于ArrayList和List而言,基本上差别不大,一样也有对MoveNext和Current以及IDisposable接口的调用。只不过ArrayList多出unbox和box的指令。

运行结果如我们所料,List要比ArrayList快不少。

但是我们在枚举部分的代码是有问题的,我明天在(下)中会介绍。