笔记4

如果在1.0中我们可以有以下三个方法可以解决:
1.为decimal搞一个向引用类型转换的wrapper

2.为价格未知的产品增设一个bool类型的flag标记位

3.使用一个”magic value”,比如decimal.MinValue来表现一个未知的价格

在2.0中

public decimal? Price { get; private set; }

恩,类型前面有一个问号,这就代表了Price是可以赋值为null的,那查询语句中就可以这样写~

            List<ProductWithNullablePrice> products = ProductWithNullablePrice.GetSampleProducts();

            foreach (ProductWithNullablePrice product in products.Where(p => p.Price == null))

            {

                Console.WriteLine(product.Name);

            }

本文的前几个例子并没有升入,只是浅显的描述了语言的变化,本文下面介绍的LINQ我就不多说了,无论LINQ TO SQL,LINQ TO XML,LINQ TO Obect等等其实都差不多。

 

下来还是讲讲C#的历史以及故事吧~:D

话说我们还是先得从java说起。如果没有java那么就不会有.net,这个话题已经相信已经争论过无数次了,但其实要说没啥影响也不大可能。Java诞生于1996年1月份,从那以后整个世界就陷入了java mad…

简单说来,那个时候的java是非常慢的,大多数的applet在web上几乎都无用武之地。自从(JITS),即时编译器引入以后速度才得到改观,从此开发者们才将其开发从客户端转移到了服务器端。从那以后java发展很快,更被灌予了wirte once,debug everywhere,write once,run everywhere。开发者们在windows上开发java应用程序,然后部署到了Unix下面,这一世人皆知的行为很明显的给微软带来了威胁。

微软也搞了自己的java虚拟机(JVM),在启动时间以及性能上都有了很大的提高,还有IDE,取名叫做J++.

然后它却不能进行其他平台的扩展。这让SUN很不爽啊,直接告了微软侵犯版权,开始了一场漫长的官司~

这张官司最大的影响就是-当java发现到了1.2甚至更高,微软的还处在1.1的时代,这让它很快的过时了。

很明显的就是,不管微软未来的版本是什么,java不大可能成为它主体的一部分.(不大懂什么意思…)

与此同时,微软搞了ASP(active server page),它也获得了不少的关注。在1996诞生之后,1997年和2000年又诞生了2个版本。ASP让DHTML更加容易了,而且终于可以移植到非微软平台上了。尽管这是web发展的一大步,但是它却没有很好的把表现层,逻辑层与数据访问层区分开来(我们这公司还你妈写ASP呢,一个页面看看天没看出个究竟),而这种分层结构却是java web框架所一直提倡的。

这样看太慢了啊,之说重点和看的不太懂的东西了。

 

delegate的变化

假如有如下一个委托类型

delegate void StringProcess(string str);

那么与之匹配的方法是否能像这样吗?

Void PrintString(object obj)

嗯哼,看样子是可以的嘛,string不就是一个object吗,其实在1.0中参数是严格匹配的,在2.0以上中才能这样用~

其实这是委托中一个叫做协变(covariance)的东西,当然还有一个叫做逆变(contravariance)的东西。

 

委托实例的调用其实可以是 :委托调用-委托invoke调用-真正方法调用

其实是一个invoke在起作用

委托链 可以用加减来表示委托方法的增加或减少

[a,b]+[b,c]=[a,b,b,c]不会因为相同而减少一个b的实例

想象方法总是要依次调用的嘛

而[a,b,c,d,e]-[a,c,e]=[a,b,c,d,e]

就是说一个委托链的方法-另外一个委托链的方法,后面的委托链必须是前面委托链的连续子集。

委托对于事件之于属性对应字段delegate-evnet property-field

 

类型安全

Static typing vs dynamic typing

一个很简单的例子,length属性能够动态适应字符串或者集合,应该能正确处理,这就是动态与静态的区别之一。

 

Explicit typing vs implicit typing

这个就不用多说了,想想Js中随便怎么赋值

 

Type safe vs type unsafe

对于c语言,编译器会“推断”,也许会把char pointer当成一个 int pointer,从而会有意想不到的结果,这其实就是编译器的trick.肯定会给带来不少困惑。

 

为什么说C#1中的类型体系还不够丰富

首先是集合:

假如有如下代码:

string[] str = new String[5];

object[] obj = str;

obj[0] = new object();

如果在1.0中运行以上代码在第三行就会有ArrayTypeMismatchException的异常(没试过,书上说的)

为什么呢,因为当str赋值给obj时,obj得到的是一个str的原始引用,也就是说str和obj只能接受string的赋值操作,CLR2中协变解决了这一问题。

那如果是换成通用一些的集合呢,譬如HashTable和ArrayList之类会怎么样呢,这些集合其实在内部采用一个object类型的key value,因此在编译时不会有什么问题,但其实这就导致了类型安全的问题,因为这些集合在编译期根本就不知道集合中是什么东西。因此,当你需要操作一个string集合的话,如果你想得到该集合中的string,那么你必须显示的进行一个危险的cast.这就是是所谓的“弱类型集合”。

那么下来我们考虑一下“强类型集合”,譬如StringCollection.你会很有信心,嗯哼,这下总不错了吧,只能是一个string的集合诶,得到这个集合中某一个字符串也不用再进行什么cast啦,哦也~

听起来不错,实际上还是有问题滴,首先,因为它实现了IList接口,所以add操作还是可以将一些乱七八糟的东西add进去,虽然会在运行时报错。再者,它只能处理string类型的集合,那么其他的东东呢,咋整。当然,你可以会说,别忘了,我们还有CollectionBase呢,我自己去实现一个自己的强类型集合去,恩,如果你不怕麻烦,just do it~

 

逆变与协变

…不多说了,现在只能算是理解。(针对返回值的是协变,参数类型的逆变)

 

学了个duck typing,

Wiki中这样解释:

在程序设计中,duck typing是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试(见下面的“历史”章节),“鸭子测试”可以这样表述:

“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”[1][2]

在duck typing中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用duck typing的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用duck typing的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。

Duck typing通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。从静态类型语言转向动态类型语言的用户通常试图添加一些静态的(在运行之前的)类型检查,从而影响了duck typing的益处和可伸缩性,并约束了语言的动态特性。

 

还是看代码最好理解:

function calculate(a, b, c) => return (a+b)*c

 

example1 = calculate (1, 2, 3)

example2 = calculate ([1, 2, 3], [4, 5, 6], 2)

example3 = calculate ('apples ', 'and oranges, ', 3)

 

print to_string example1

print to_string example2

print to_string example3

 

在样例中,每次对calculate的调用都使用的对象(数字、列表和字符串)在继承关系中没有联系。只要对象支持“+”和“*”方法,操作就能成功。例如,翻译成Ruby或Python语言,运行结果应该是:

9

[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]

apples and oranges, apples and oranges, apples and oranges,

 

好了总结一下把:(关于C#1)

是静态类型-编译器知道什么类型你可以谁用什么你不可以使用

是显视的,你必须告诉编译器这个变量是什么类型

是安全的,不支持隐式转换。

静态类型并不意味着允许集合诸如强类型(string的集合 或者Int的集合)

么有协变以及逆变

 

接下来一个话题其实还是老生常谈咯 value type and reference type

很有意思,本书对于值类型和引用类型的比喻还是挺有意思的,我在此记录下来

 

什么是值类型?故事开始:

你有一份非常不错的资料,刚好被你的同学小张看到了,于是他也想看啊,可是你并不想借给他,因为你最近要考试了嘛,怎么办,去复印一份咯,于是把你的资料拿到学校的打印室。这下就好了,你的资料还是你的资料,与此同时,你的同学小张也有了这份资料的一个拷贝。这个时候,你的资料和他的资料就区别开了,你们俩可以在各自的资料上做不同的笔记,你在你的资料上做的笔记不会印象到小张的资料,同理于小张的资料。这就是值类型。

 

什么是引用类型:

想象一个网页,当你浏览一个网页,其实你是通过指向其地址的URL才能进行浏览的。要想浏览某一个网页,你必须知道某一个URL,这就类似于引用类型的指针。与此同时,如果是wiki的网站,你在某一个网页增加了一些内容,那么别人通过相同URL访问过来同样会浏览到这些增加的内容。

 

值得注意的是:enum是值类型,而System.Enum是引用类型。

书上说值类型和引用类型的一大区别之处是值类型不能够继承。错!能继承于接口啊,还能多继承呢~

看完它说的几个所谓myth。

  1. struct是一个轻量级的class
  2. 引用类型永远在heap上,值类型永远在stack上。(前一句正确,后一句就…假如一个类里面有一个Int型的Field的话….)
  3. objects在C#里默认是引用传值(其实所有的传值默认都是值类型传值,文中强调说不是object在传递,而是reference在传递)

接下来还要讲另外的myth,装箱拆箱,好了,今天就看到这吧。

posted @ 2010-04-14 15:09  Tmac_  阅读(58)  评论(0)    收藏  举报