Allen Lee's Magic

这里没有答案,顶多给你几个值得一试的猜想。

我眼中的C# 3.0

我眼中的C# 3.0

 

Written by Allen Lee

 

缘起

每次有新技术发布时,我们总能感受到两种截然不同的情绪:一种是恐惧和抵抗,伴随着这种情绪的还有诸如"C# 2.0用的挺好的,为什么要在C# 3.0搞到那么复杂?"或者"我还在使用C# 1.0呢?"等言辞;另一种则是兴奋和拥抱,伴随着这种情绪的还有诸如"原来这个问题在C# 3.0里可以这么简单!"等言辞。

最近我在公司内部做一个LINQ的系列讲座,在我为其中C# 3.0新特性这一讲准备演示文稿时,突然萌生了写下这篇文章的念头。语言的特性乃至其本身并没有对错之分,是否接受在很大程度上是一个感性问题,即你是否喜欢这样的做事方式,我并没有打算说服任何人接受C# 3.0和LINQ,写这篇文章也只是想和大家分享一下我自己的感受。

有一次我观看一个关于Expression Blend的培训视频,里面说了一句让我印象非常深刻的话:

I know how it works because I know why it works.

细细品味这句话,你会感受到它所要传达的信息:理解为何需要这个功能可以帮助你更好地理解如何使用这个功能,而这也正是我要在这篇文章里采用的表达方式。

 

你是如何创建属性的?

如果你长期使用C#,相信你不会对属性这个东西感到陌生。一般地,属性是对私有字段的一个简单包装,就像这样:

代码 1

使用属性而不是直接公开私有字段的一个好处就是在属性的获取访问器或设置访问器里加入额外的逻辑并不会为客户端代码带来麻烦,例如你想在设置标题的时候做一些额外的检查。但如果你只是简单地包装一下,像上面的代码那样,就会发现你其实多写了不少可以省略的代码。既然Title属性和m_Title私有字段对应,获取访问器就肯定是返回m_Title的值,而设置访问器也肯定是把值设到m_Title。再者,如果你只通过Title属性来访问这个数据,那么m_Title私有字段就会变得无足轻重,这样的话,为什么不交给编译器代劳呢?这个时候,C# 3.0的自动属性就可以派上用场了:

代码 2

编译器会为你创建一个私有字段,并让获取访问器和设置访问器指向这个私有字段。当然,如果有需要,例如要在获取访问器或设置访问器里加入额外的逻辑时,你随时可以对获取访问器和设置访问器进行展开。

 

你是如何初始化对象的?

现在,假设我们有这样一个类:

代码 3

你会怎样初始化它?一种做法是用Book的默认构造函数创建对象实例,然后分别为每个属性赋值:

代码 4

另一种做法是使用C# 3.0对象初始化器:

代码 5

乍看一下,C# 3.0的做法似乎没有让人感到任何优越感,现在,请你仔细观察一下,这两份代码分别包含多少个";"?代码4有5个";",意味着它用了5个语句进行初始化;而代码5只有1个";",意味着它只用了1个语句进行初始化。从词法的角度来看,如果此刻我只能接受一个表达式,那么代码4的做法就帮不上忙了。一个变通的方法是为Book类提供带参的构造函数,但这种方法也有弊端,用户可能只想在初始化时为部分属性提供数据,而我们又无法确切预知用户会提供哪些属性的组合,于是,我们可能要为用户提供足够多的构造函数重载,嗯,有点无聊,也有点多余。另一个变通的方法是提供接受最多参数的构造函数,如果用户为某个参数传递null,那么就忽略与之对应的属性,这个方法比较接近代码5的做法,不同的是,如果你的属性很多,而用户关心的只是很少一部分,就可能不得不输入很多null了。

现在,假设你要实例化一组Book对象,并把它们储存在一个集合里,你会怎么做?下面是通常的做法:

代码 6

如果结合使用C# 3.0的对象初始化器和集合初始化器,你就可以把代码简化为:

代码 7

集合里的每个元素通过","分割,结合对象初始化器使用,整个集合的结构显得比较明晰。字典的初始化也可以同样简单:

代码 8

说到这里,我相信你也能感觉到,C#似乎正在表达式化,以前需要很多条语句才能做到的事情,现在却可以用单个表达式描述出来,而这种理念也渗透在整个C# 3.0的氛围里。

 

你是如何把运算逻辑外包出去的?

假设我现在得到了一组Book的实例对象,你要对它们进行排序,那么你如何告诉它你要按价格来排序呢?

代码 9

在C# 1.0里,我们需要特意为它提供一个独立的方法:

代码 10

然后向Sort()方法传入所需委托的实例:

代码 11

这在C# 2.0里可以进一步简化为:

代码 12

如果使用C# 2.0的匿名方法,我们可以省去很多不必要的代码:

代码 13

此外,使用匿名方法,Sort()方法和你希望它用来比较两个Book实例对象的逻辑可以放在同一个地方;而使用独立的命名方法,包含这个逻辑的方法可能会由于整理代码而被挪到别的地方。这样,当你看到代码12时,为了了解它内部的实现,就不得不花一些精力去寻找Compare()方法了。当然,你可以争辩说,我们可以制定一个编码规范,使得Compare()方法必须紧贴在Sort()方法的下方。是的,你可以,但如果这个逻辑并不需要重用,那么使用匿名方法还是具有明显的优势的。如果这个逻辑需要重用,那么匿名方法就无能为力了。

现在,让我们来考察一下代码13,有没有发现匿名方法的表达方式还不够简练?我们知道,books集合里面只有Book的实例对象,所以Sort()方法传给我们两个参数的类型必定是Book,而Sort()方法期待的结果正是x.Price.CompareTo(y.Price)这个表达式的运算结果,至于delegate和return这样的字眼可以说在这里完全是多余的,那么为什么我们不直接这样表达呢:

代码 14

这就是C# 3.0引入的Lambda表达式语法。我见过一些人,他们通常强调尽可能简单,但若事情突然变得比他们预期的还要简单很多,他们就开始感到不适,甚至拒绝接受这种简单,其实即使事物的发展方向和你的前进方向相一致,但如果发展速度大大超越了你,仍然有可能引发你内心对失控的恐惧。我希望Lambda表达式语法不会让你感到太大的不适,当然我更希望你会喜欢上它。

Lambda表达式的理解其实可以很简单,就是"=>"左边的参数参与右边的表达式运算,而运算结果将会返回,这有点像化合反应,即两种或两种以上的物质(左边的参数)生成一种新物质(右边的表达式的运算结果),不同的是,Lambda可以不接收任何参数,也可以不返回任何结果。

"=>"右边除了可以放表达式之外,还可以放语句,像这样:

代码 15

我们把它称为Lambda语句(Lambda Statement),或许你已经发现,它和匿名方法相比只是不需要写delegate关键字和参数类型。

 

你是如何为对象扩展与之相关的功能的?

我一直在想,为什么String类没有提供一个Reverse()方法,把字符串翻转呢?我猜可能是因为这种操作没有什么现实意思,除非你要做一个文字游戏。实现Reverse()方法并不难,下面是其中一种做法:

代码 16

使用方法也非常简单:

代码 17

你甚至可以把Reverse()方法放到某个静态类里,例如Utils,这样,代码17就可以变成:

代码 18

在C# 3.0之前,你最多只能走到这里,而到了C# 3.0,你还可以使用扩展方法对它做进一步调整,使代码18变成:

代码 19

怎么样,看上去就像Reverse()方法是属于String的,而你所需要做的仅仅是在Reverse()方法的target参数前面加上"this"关键字:

代码 20

我们知道,计算机的底层世界并不知道什么是面向对象,而我们在对象里定义的实例方法都包含一个隐藏参数,这个参数就是指向当前对象实例的指针,C# 3.0的扩展方法在形式上模仿了这种做法,但由于扩展方法本质上并不属于与之相关的类,所以你无法在扩展方法里访问类内部的私有成员。

就上面的讨论来说,你可能认为,和代码18相比,代码19并没有太大的优势,那么为什么需要扩展方法呢?假设我们手头上有一堆书,我想找到最便宜的LINQ的书,使用标准查询运算符的话可以这样写:

代码 21

我们知道,Where()、OrderBy()和First()等都是扩展方法,如果C# 3.0不支持扩展方法,那么代码21就不得不写成这样了:

代码 22

代码21的可读性明显比代码22的高,也显得更自然,而此时我们只是使用了3个标准查询运算符,你可以想象一下,在没有扩展方法的支持下要表达更复杂的查询会是怎样一番情景?

 

你是如何表达你想要的东西的?

现在,假设我想找到最便宜的LINQ的书,使用C# 2.0的语法,我可能需要这样:

代码 23

虽然我已经使用了Array.IndexOf()方法、List<T>.Sort()方法和匿名函数来简化代码,但仍然无法掩盖一个事实,那就是我在讲述如何获取我想要的东西,而这也正是命令式编程(Imperative Programming)的核心思想。

如果使用C# 3.0的语法,情况将会大不一样:

代码 24

在这里,你表达了你想要的东西,而不是获取这些东西的具体步骤,这是声明式编程(Declarative Programming)的核心思想,这样做的好处是明显的,你的需求可以被重新解析并执行,必要时还可以对底层的实现进行优化,但由于你并不关心和牵扯到具体的实现上,所以那些优化并不会导致你修改代码。

命令式编程就像过程管理,你深入执行的细节,继而对整个过程的执行实施控制;而声明式编程则像目标管理(MBO),你制定目标,并把任务分配下去执行。代码23给人的感觉就是整个执行过程都非常的清楚,你可以对任何一个步骤进行修改或者调优;而代码24给人的感觉就是你除了说出你想要什么,你什么也不能做,这对于那些过程管理拥戴者来说可能是不可接受的,他们感到对事物失去了控制,无法建立安全感,因而产生了焦虑。曾经有人向我抱怨:如果你使用了LINQ,你就只能迫使自己相信它的实现是很好的。想想看,如果你的公司把饭堂业务承包给一个餐饮公司,你的公司可以插手别人如何招聘厨师、如何采购食物、如何烧菜烧饭吗?选择LINQ意味着你愿意把执行细节交给别人去处理,从而脱离这些细节,如果你根本无法放下对这些细节的控制,那么LINQ可能并不适合你。

很难说这两种编程方式孰优孰劣,因为在某些场合下,善于过程管理的管理者确实更能让事态朝正确的方向发展;而在另一些场合下,目标管理为实现者提供足够的自由度,更能激励他们积极地进行思考。管理界对于过程管理和目标管理孰优孰劣之争论似乎从来没有停过,更何况编程界对于命令式编程和声明式编程孰优孰劣之争论,我个人倒是更倾向于把这看成是找出更适合你自己的风格,而不是盲目听信别人的说法。语言到底是发挥积极作用还是消极作用在很大程度上是取决于使用者的,我们应该使用语言有利的一面来协助我们的工作,而不是使用其有害的一面来伤害自己和别人。

回到代码24,它把满足条件的书的所有信息都返回给我,如果我只需要书名和作者名字呢?我们知道,在面向对象的世界里,信息储存在对象里,于是我们不得不走到一个尴尬的境地,那就是我们要为此创建一个临时类:

代码 25

噩梦正式开始了,如果我需要书名和价格呢?如果我需要书名、作者和价格呢?……(读者可以自行补全这个列表)这个时候就轮到C# 3.0的匿名类型和隐式类型化变量出场了:

代码 26

因为匿名类型是由编译器自动生成的,而在你写代码的时候它还没有名字,所以你无法用这个类型来声明这个变量,此时"var"关键字就派上用场了。这个是"var"关键字的最初目的,但得益于类型推断系统,我们还可以使用"var"关键字声明任何本地变量,只要我们在声明的同时给予它初始化,否则编译器无法进行推断。曾经有人问我:如果我想返回代码26里的wanted7怎么办?我们知道,方法的返回值需要明确给出类型,而在我们写下代码26时,编译器还没有给查询表达式里的匿名类型取名。如果你真的要把它返回,你只能把方法的返回值类型定为IEnumerable<object>,因为我们只能确定匿名类型是object的后代,但这样一来,客户端代码的日子就不太好过了,因为除了通过反射来访问你的对象,它别无他选。如果你真的要把它返回,那就意味着你和客户端代码有共享这个对象的需求,此时恰当的做法应该是使用命名类型。另外,代码26里构建匿名类型时的"book.Title"是"Title = book.Title"的简写,当你省略"Title ="时,编译器会假定你希望匿名类型的这个属性的名字和Book.Title的一样。

匿名类型还有一个有趣的地方,它曾经是可变的(mutable),后来却变成不可变的(immutable),Sree《Immutable is, the new Anonymous Type》一文中给出了这个转变的解释。我们知道,在面向对象的世界里,对象封装并维护自身的状态,我们通过调用对象的方法所产生的副作用来影响对象的状态,而不可变则是函数式编程(Functional Programming)的核心特征,或许你已经感受到了,C# 3.0引入了大量函数式编程的东西,而函数式编程语言似乎也要风生水起,这究竟意味着什么呢?

 

前路在何方?

无论你是否承认,C# 3.0在表达上比它之前的版本要来的简单,但要获得这种简单,你必须先用很多东西武装自己的脑袋,这使我想起曾经在一本书里看到的一句话:

简单是由复杂来支撑的。

不同语言之间的相互渗透已经不再是什么新奇之事了,引入其它语言的功能有时候甚至可以看作是在战略上入侵对手的市场,这在某种程度上有点像金融业的混业经营。下一个版本的C#将会是怎样的呢?或许这个问题令你兴奋不已,你甚至希望现在就让C# Team看看你的创造力;或许这个问题令你痛心不已,你害怕自己无法适应下一波的变革,因为变革可能导致动荡,动荡可能带来失控,失控可能引发焦虑。不管怎样,该来的是无法回避的,或许现在先让我们看看Matthew Podwysocki的《What Is the Future of C# Anyways?》是否有一些启示……

 

附:如果你有兴趣看看我的演示文稿,可以点击这里下载。

Tag标签: C# 3.0,LINQ

posted on 2008-06-01 10:49 Allen Lee 阅读(8633) 评论(112)  编辑 收藏 所属分类: C#

评论

#1楼 2008-06-01 11:01 真见      

强。   回复  引用  查看    

#2楼 2008-06-01 11:15 xrainfir      

原来还可以这么写属性 倒了 才知道   回复  引用  查看    

#3楼 2008-06-01 11:28 李永京      

分析的很好啊,呵呵!   回复  引用  查看    

#4楼[楼主] 2008-06-01 11:38 Allen Lee      

@真见
@李永京
谢谢!
  回复  引用  查看    

#5楼[楼主] 2008-06-01 11:40 Allen Lee      

@xrainfir
在C++/CLI里,属性可以更简单:

public: property String^ Title;

如果你有兴趣,可以看看MSDN上的介绍:http://msdn.microsoft.com/en-us/library/es7h5kch.aspx" target="_new">http://msdn.microsoft.com/en-us/library/es7h5kch.aspx
  回复  引用  查看    

#6楼 2008-06-01 11:43 Anders Cui      

这才叫引人入胜 :P   回复  引用  查看    

#7楼 2008-06-01 12:15 丁学      

我见过一些人,他们通常强调尽可能简单,但若事情突然变得比他们预期的还要简单很多,他们就开始感到不适,甚至拒绝接受这种简单,其实即使事物的发展方向和你的前进方向相一致,但如果发展速度大大超越了你,仍然有可能引发你内心对失控的恐惧。
------------------------------------------
估计好多人是这种心理,虽然真的希望一件事情能够变好,但一旦它变得你感觉不可控,恐惧感便油然而生
  回复  引用  查看    

#8楼 2008-06-01 12:22 水言木      

写得很好!!学习了。   回复  引用  查看    

#9楼 2008-06-01 12:33 Jeffrey Zhao      

写的相当好啊。   回复  引用  查看    

#10楼 2008-06-01 12:44 haho[未注册用户]

演示文稿是什么做的呀,
我下载下来为什么打不开?
  回复  引用    

#11楼 2008-06-01 12:56 kuafoo3[未注册用户]

非常好 看了这篇文章 让我觉得保守不是一件好事情   回复  引用    

#12楼[楼主] 2008-06-01 13:01 Allen Lee      

@Anders Cui
过奖啦~~~
  回复  引用  查看    

#13楼[楼主] 2008-06-01 13:03 Allen Lee      

@丁学
我不知道这种人有多少,估计这种人遇到敏捷的话可能也要疯掉,呵呵~~~
  回复  引用  查看    

#14楼[楼主] 2008-06-01 13:03 Allen Lee      

@水言木
谢谢!
  回复  引用  查看    

#15楼[楼主] 2008-06-01 13:04 Allen Lee      

@Jeffrey Zhao
今天老赵也来捧场啦,儿童节不出去玩么,呵呵~~~
  回复  引用  查看    

#16楼[楼主] 2008-06-01 13:05 Allen Lee      

@haho
演示文稿是2007版的PowerPoint Show。
  回复  引用  查看    

#17楼[楼主] 2008-06-01 13:13 Allen Lee      

@kuafoo3
保守和谨慎乃一纸之隔,合理的谨慎有助于降低风险,但谨慎有时候会被用来粉饰保守,这种做法是愚蠢的,最终也会为此而付出代价。
  回复  引用  查看    

#18楼 2008-06-01 13:30 江水滔滔      

條理很清楚!   回复  引用  查看    

#19楼 2008-06-01 13:38 CoderZh      

写的太好了!   回复  引用  查看    

#20楼 2008-06-01 13:40 炭炭      

抵抗是幼稚的,拥抱是必须的   回复  引用  查看    

#21楼 2008-06-01 13:58 废墟中的垃圾      

其实程序员越来越明显的被分化。
从.net出来那天起就已经开始转化,越来越多的人变成应用程序员。

从我第一天学程序那天开始,我就遵从一个原则,就是思之根本,学之技巧。大部分的人都是从学一语言开始,比如新的程序员可能直接c#3.0, 不会经历1.0,1.1.,2.0的阶段,大部分学习的都是新的语法,以后还会有4.0,5.0。

这里经历过1.0到现在3.0的人应该不少,最少经历2个以上版本的人应该很多,但是我相信能写出来博主的26个演变过程代码的人不多。

希望那些纯应用的程序员,就不要太叫嚣。真正的好程序员最少要写出来上面转变吧,向博主学习 :) mark
  回复  引用  查看    

#22楼 2008-06-01 14:03 LuChaoShuai      

很好.很强大...
这是我见过的,最好的C#3.0教程.
  回复  引用  查看    

#23楼 2008-06-01 14:18 Beginor      

楼主的表达能力真好,佩服!   回复  引用  查看    

#24楼 2008-06-01 14:23 Train-8[未注册用户]

高!   回复  引用    

#25楼 2008-06-01 14:27 kabal      

好文!   回复  引用  查看    

#26楼 2008-06-01 14:33 omnislash      

读这样的文章真是一种享受,多谢博主啦~~   回复  引用  查看    

#27楼[楼主] 2008-06-01 14:37 Allen Lee      

@江水滔滔
@炭炭
过奖了!
  回复  引用  查看    

#28楼 2008-06-01 14:41 Jeffrey Zhao      

我是激进派了,如果一个新事物出现,我更倾向于去了解它,看看它到底能否帮助我,而不是怀疑它的作用呵呵。   回复  引用  查看    

#29楼[楼主] 2008-06-01 14:46 Allen Lee      

@炭炭
事物的本质有时候并不像它表现出来的那样,关键并非拥抱或者抗拒,而是正确的思考,就像在股票市场,关键不是看涨或者看跌,而是看对 :)
  回复  引用  查看    

#30楼 2008-06-01 14:50 小新0574      

你也好就不写文章了吧,支持一下好文:)   回复  引用  查看    

#31楼[楼主] 2008-06-01 14:54 Allen Lee      

@LuChaoShuai
真的吗?如果这篇文章能让那些还在犹豫的人至少产生那么一丁点试一下C# 3.0的想法,那就是我最大的荣幸了!
  回复  引用  查看    

#32楼[楼主] 2008-06-01 14:55 Allen Lee      

@Beginor
@Train-8
@kabal
谢谢!
  回复  引用  查看    

#33楼 2008-06-01 14:56 xrainfir      

@Allen Lee

谢了 我看了已经 :-)
  回复  引用  查看    

#34楼[楼主] 2008-06-01 15:01 Allen Lee      

@omnislash
你的评论给我很大的激励啊~~~
  回复  引用  查看    

#35楼[楼主] 2008-06-01 15:05 Allen Lee      

@Jeffrey Zhao
用销售的行话来说,你是“早期接受者”,呵呵~~~

与此相对的是“晚期接受者”,他们会等到新技术被试用并被大多数人验证后才会采用。
  回复  引用  查看    

#36楼[楼主] 2008-06-01 15:09 Allen Lee      

@小新0574
你也冒泡啦,今天是儿童节啊,有没有看《蜡笔小新》啊?
  回复  引用  查看    

#37楼 2008-06-01 16:17 fyxruben[未注册用户]

感觉在向动态语言靠近。。。   回复  引用    

#38楼 2008-06-01 16:21 airwolf2026      

哇.嘎嘎.好文   回复  引用  查看    

#39楼 2008-06-01 16:23 金色海洋(jyk)      

我觉得C#有两个方面一直在“学习”VB。
第一个方面是IDE,第二个方面就是简便的写法。

比如在vb.net里面可以这么写

Public Sub myBind(ByVal obj As Object)
...
'获取记录集,然后绑定控件,控件有外部传入,比如DataGrid、DataList等。
obj.datasource = myDataTable
obj.databind()

End Sub


但是实际上编译器会把这个转换成反射的形式。就是说编译器,为我们作了一些复杂的工作。

而第一个例子就是这种思路的一种情况。


  回复  引用  查看    

#40楼 2008-06-01 18:20 皇帝的新装      

知识的储备与使用是两码事。   回复  引用  查看    

#41楼 2008-06-01 18:36 J[未注册用户]

我有一个问题
class A { public int F { get; private set; } }
...
var a = new A { F = 1 };
...
为啥合法?
  回复  引用    

#42楼 2008-06-01 19:25 戏水      

行文通俗易懂, 内容详尽实用 。 是好文,没错!   回复  引用  查看    

#43楼 2008-06-01 19:55 cunet[未注册用户]

关于自动属性一段:“例如要在获取访问器或设置访问器里加入额外的逻辑时,你随时可以对获取访问器和设置访问器进行展开。 ”,能否解释一下具体怎样展开?如果引用编译器自动创建的私有字段?   回复  引用    

#44楼[楼主] 2008-06-01 20:00 Allen Lee      

@ J
这个代码会出现编译时错误,怎么算得上合法呢?
  回复  引用  查看    

#45楼[楼主] 2008-06-01 20:05 Allen Lee      

@cunet
编译器自动创建的那个私有字段是无法引用的,如果你需要对自动属性进行展开,那就意味着你关心私有字段,此时你就应该自行创建这个私有字段。这里的“展开”其实就是指用普通的方法重新创建这个属性,由于对外这个属性的名字、类型等都没变,故称之为“展开”。 :)
  回复  引用  查看    

#46楼[楼主] 2008-06-01 20:06 Allen Lee      

@airwolf2026
@戏水
谢谢!
  回复  引用  查看    

#47楼 2008-06-01 20:10 果果’er      

订阅allen的blog以来看到的首发 :)

最近用到一些这方面的东东。感觉基本上都是使用编译器来实现一些有效的新特性,好处是仍然保留了原来强类型语言编译时检查错误的特点。

楼上cunet说的展开,我想allen是指自己写成手写的方式吧 :)
有时在重构的时候就需要这样做了。
比如需要给一个特殊的默认值?
  回复  引用  查看    

#48楼[楼主] 2008-06-01 20:16 Allen Lee      

@金色海洋(jyk)
这应该就是VB.NET的Late Binding吧?据我所知,VB.NET本身就具备成为动态语言的潜质。
  回复  引用  查看    

#49楼[楼主] 2008-06-01 20:24 Allen Lee      

@果果’er
说对了,我所说的“展开”其实就是“人工重构”,呵呵~~~

你订阅了我的Blog吗?不好意思啊,这么久才发一篇~~~
  回复  引用  查看    

#50楼 2008-06-01 20:27 戏水      

@ Allen Lee
我觉得 《蜡笔小新》 是成人动画片~~!!
  回复  引用  查看    

#51楼[楼主] 2008-06-01 20:32 Allen Lee      

@皇帝的新装
是的,所以这个世上既有企业家也有咨询师。
  回复  引用  查看    

#52楼[楼主] 2008-06-01 20:35 Allen Lee      

@戏水
这就对了,因为小新0574已是成人,呵呵~~~
  回复  引用  查看    

#53楼 2008-06-01 20:39 果果’er      

@Allen Lee:
上次搜索过来看到篇很好的文章,当然要订下来了。

开始写C#3.0,又有得看了 :)
  回复  引用  查看    

#54楼 2008-06-01 21:06 Tristan(Guozhijian)      

hi, allen
上次看你讲那么久,也许比较辛苦,就没有继续请教你这个问题
在这里我顺便提下

我是说,在LINQ To SQL的from .. in .. where... select new {} 这样的statement里面, 似乎在 select new {}的大括号里面有些FCL内建的方法是不能使用的,比如 某个datetime型的数据库字段, 把它转成string型时会报错.

如 from ... in ...
where ...
select new {PublishDate = Book.PublishDate.ToString("yyyyMMdd")}

这让我很苦恼啊.
  回复  引用  查看    

#55楼 2008-06-01 21:07 Tristan(Guozhijian)      

我想是因为编译器在生成SQL Command的时候,不知道怎么翻译这些方法吧?   回复  引用  查看    

#56楼[楼主] 2008-06-01 21:23 Allen Lee      

@Tristan(Guozhijian)
是的,如果查询表达式里使用了LINQ to SQL不知道如何翻译成SQL语句的方法,就会报错。
  回复  引用  查看    

#57楼 2008-06-01 21:50 Anytao      

很久了,没有读如此精彩的论述,还是坚持一直以来的风格,Lee式风格:-)   回复  引用  查看    

#58楼 2008-06-01 22:09 kiler      

好文,比较喜欢这种浅显易懂的文章。   回复  引用  查看    

#59楼 2008-06-01 23:24 BlackPhoenix      

让我这种还没开始学3.0的人都可以理解,而且有用!   回复  引用  查看    

#60楼 2008-06-01 23:59 lexus      

例子相当不错,   回复  引用  查看    

#61楼 2008-06-02 02:10 求知无傲      

暂时不想学。以后再说呗。   回复  引用  查看    

#62楼[楼主] 2008-06-02 07:56 Allen Lee      

@Anytao
你的“王氏物语”很深受大众的欢迎啊,呵呵~~~
  回复  引用  查看    

#63楼[楼主] 2008-06-02 07:56 Allen Lee      

@kiler
@lexus
谢谢!
  回复  引用  查看    

#64楼[楼主] 2008-06-02 07:57 Allen Lee      

@BlackPhoenix
你让我深信这篇文章没有白写~~~
  回复  引用  查看    

#65楼[楼主] 2008-06-02 08:02 Allen Lee      

@求知无傲
或许你心里已经有了一个计划,不想被突如其来的学习C# 3.0打乱,如果你确实用不上C# 3.0,那不学也罢,但希望你不要等到非学不可的时候才学,因为那个时候事情可能会更乱。
  回复  引用  查看    

#66楼 2008-06-02 08:50 MIC[未注册用户]

现在,请你仔细观察一下,这两份代码分别包含多少个";"?代码4有5个";",意味着它用了5个语句进行初始化;而代码5只有1个";",
胡说什么了,你去看下生成的中间语言吧.这只是对代码编写的一种优化,底层是怎样还是怎样
  回复  引用    

#67楼 2008-06-02 09:05 qmxle[未注册用户]

写得真好!

C#3.0了提供了这些“语法糖”,可以让我们把简单的事情保持简单。而如果需要复杂的时候,它又能够支持。

我觉得很好。
  回复  引用    

#68楼[楼主] 2008-06-02 09:57 Allen Lee      

@MIC
稍安勿躁,众所周知,C# 3.0的新特性仅限于语法层面,并未触及IL层面。如你所说,在IL层面,代码4和代码5基本上是一样的,但它们在C#的词法/句法层面就不同了。比如说,我现在有这样一个类:

class BookData
{
public string Title { get; set; }
public double Price { get; set; }
}

我要在代码26的select里构建BookData的实例,以便返回给客户端代码,此时,代码4的做法很明显是无能为力,因为select里要求的是一个表达式(expression)而不是一组语句(statement)。

我相信你会同意C语言在表达上比汇编语言更直观,我也相信你会认同C语言和汇编语言写出来的东西最终在机器代码层面都没有本质的区别,进步究竟是怎么一回事,历史很多时候已经把答案告诉我们了。
  回复  引用  查看    

#69楼 2008-06-02 10:17 aaa fff[未注册用户]

正是c#3.0 这种语法糖,才造就了大量的半桶水程序员.如果一个人直接从3.0开始,他可能对某些东西一知半解就开始编程了,所以C语言和java语言的稳定是有一定道理的.   回复  引用    

#70楼 2008-06-02 12:49 簡簡單單..      

Mark   回复  引用  查看    

#71楼 2008-06-02 13:21 行知      

写的很好,受教了。   回复  引用  查看    

#72楼 2008-06-02 13:28 哈哈熊      

不错,前几天正好看了一下Linq,很好很强大。   回复  引用  查看    

#73楼 2008-06-02 14:45 MIC[未注册用户]

@Allen Lee
意味着它用了5个语句进行初始化;而代码5只有1个";"
哈哈看来还是表达上的事,这句话改改就好了.新手准上你这句话的当
  回复  引用    

#74楼 2008-06-02 14:50 redmoon      

在某些情况下,越简单的东西蕴含的东西也就越深奥。   回复  引用  查看    

#75楼[楼主] 2008-06-02 18:45 Allen Lee      

@aaa fff
我看不出“所谓的C#3.0的语法糖”和“大量半桶水的程序员”之间有直接的因果关系。在某种程度上,每个人都是半桶水,不但水平面在改变,而且桶的高度也在改变。很难说水的深度和桶的高度的比值要到多高才能使用这个知识或者技术,只能说一般情况下这个比值越高做的也越好。每个人对于如何提高这个比值都有自己的一套方法,这篇文章只是讲述了我个人的看法而已。
  回复  引用  查看    

#76楼[楼主] 2008-06-02 18:46 Allen Lee      

@行知
@哈哈熊
谢谢!
  回复  引用  查看    

#77楼[楼主] 2008-06-02 18:58 Allen Lee      

@redmoon
以前读过张景中院士的《数学与哲学》,里面提到的数学家们探讨“自然数是什么”的历史就恰恰反应了这点。
  回复  引用  查看    

#78楼[楼主] 2008-06-02 18:59 Allen Lee      

@MIC
不好意思啊,看来我还得在表达上多花点功夫才行~~~
  回复  引用  查看    

#79楼 2008-06-02 23:41 T.Johnny      

"I know how it works because I know why it works."
It is very right.
  回复  引用  查看    

#80楼 2008-06-03 11:39 乐章      

把不简单的事表述的易学易懂,受教了   回复  引用  查看    

#81楼 2008-06-03 15:23 长沙小能      

谢谢,顺便问一下你的代码是如何搞成图片的呢   回复  引用  查看    

#82楼[楼主] 2008-06-03 18:30 Allen Lee      

@乐章
谢谢!
  回复  引用  查看    

#83楼[楼主] 2008-06-03 18:30 Allen Lee      

@长沙小能
屏幕截图。
  回复  引用  查看    

#84楼 2008-06-04 14:44 不妨沉迷      

初识3.0,不错   回复  引用  查看    

#85楼 2008-06-07 12:04 wzh19831221[未注册用户]

细节越来越多,我个人觉得没有这个必要   回复  引用    

#86楼[楼主] 2008-06-07 15:22 Allen Lee      

@wzh19831221
每个人都有权利忽略自己认为不重要的细节,只要他/她愿意承担这样做的后果,无论是好还是坏。
  回复  引用  查看    

#87楼 2008-06-21 10:14 王德水      

楼主干什么的,真的不是一般人呀,表达的贼好哇   回复  引用  查看    

#88楼 2008-06-25 12:20 Jimmy Zhang      

很好的文章啊,省下很多看书的时间。文笔也很流畅,Lee总是精品不断啊
  回复  引用  查看    

#89楼[楼主] 2008-06-25 21:33 Allen Lee      

@王德水
吾乃一名C#爱好者~~~

@Jimmy Zhang
过奖啦~~~
  回复  引用  查看    

#90楼 2008-07-03 16:35 love&tiger      

学习C#3.0,楼主强   回复  引用  查看    

#91楼 2008-07-05 19:21 //天一      

其实程序员很多都是骄傲自负的,最起码在程序世界里,所以固执的家伙都有固执的坚持。也导致了对或者错,或者没有对错。

简单是由复杂来支撑的。很好的话。

以后多来学习。。。反正学习就是为了忘记。
  回复  引用  查看    

#92楼 2008-07-08 12:58 王弈博      

感慨于博主清晰的思路和良好的态度,不得不好好的顶一下。   回复  引用  查看    

#93楼 2008-07-08 16:10 leoon[未注册用户]

写得很好.很容易理解   回复  引用    

#94楼[楼主] 2008-07-15 18:39 Allen Lee      

@//天一
“学习就是为了忘记”,你这个境界高啊,就像张三丰问张无忌还记得多少那样。
  回复  引用  查看    

#95楼[楼主] 2008-07-15 18:40 Allen Lee      

@love&amp;tiger
@王弈博
@leoon
谢谢!
  回复  引用  查看    

#96楼 2008-07-25 13:41 Visiter[未注册用户]

I know how it works because I know why it works.

细细品味这句话,你会感受到它所要传达的信息:理解为何需要这个功能可以帮助你更好地理解如何使用这个功能,而这也正是我要在这篇文章里采用的表达方式。
=======================================

其实汉语里有句话,打小老师就一直给我们说的:要知其然更要知其所以然。
  回复  引用    

#97楼[楼主] 2008-07-25 18:27 Allen Lee      

@Visiter
:)
  回复  引用  查看    

#98楼 2008-07-28 08:34 小生      

這種文章讀得一點都不累﹐好文   回复  引用  查看    

#99楼[楼主] 2008-07-28 14:08 Allen Lee      

@小生
谢谢!
  回复  引用  查看    

#100楼 2008-07-29 10:37 银河      

好文章。
在不很长的篇幅里将 C# 3.0 讲解得深入浅出,并且还比较全面,楼主的水平和表达能力相当强,佩服。
特别是在代码13和代码14关于Lambde表达式讲解得很透彻。
另外,在代码26之后提到的要将var变量返回的问题,园子是有一篇随笔提到某位老外YY的C# 4.0 的四个新特性中就有这个特性。
  回复  引用  查看    

#101楼[楼主] 2008-07-29 20:29 Allen Lee      

@银河
表面上,那个YY的特性的确可以解决匿名类型的返回问题,然而,返回值的类型是编译时确定的,加上编译器自动生成的匿名类型的名字并不文档友好,除非编译器允许通过某种方式,例如特性,来定制这个名字:

[return: AnonymousTypeName("BookPart")]
public var GetBookData()
{
    return from b in m_Books
             where b.Price < 40.0
             select new { b.Title, b.Author };
}

但这样一来,还不如创建一个命名类。另外,如果我是嵌套匿名类型的话,通过特性来定制名字就不容易了:

[return: ?]
public var GetBookData()
{
    return from b in m_Books
             where b.Price < 40.0
             select new
             {
                 b.Title,
                 Author = new
                 {
                     FirstName = b.Author.Split(' ')[0],
                     LastName = b.Author.Split(' ')[1]
                 }
             }
}

我估计C# 4.0引入这个特性的可能性不大,但如果真的被那个老外YY中了,我倒想看看Microsoft怎么实现的,呵呵~~~
  回复  引用  查看    

#102楼 2008-09-08 11:31 BlackTear[未注册用户]

微软越来越集大成了。   回复  引用    

#103楼[楼主] 2008-09-09 23:10 Allen Lee      

@BlackTear
大而全和小而精是两种不同方向的发展方式,就像超级市场和品牌专卖店一样,分别满足不同偏好的消费群体 :)
  回复  引用  查看    

#104楼 2008-10-07 15:19 Enmiky[未注册用户]

不错,浏览的人可真不少!   回复  引用    

#105楼 2008-10-07 15:19 Enmiky[未注册用户]

不错,浏览的人可真不少!   回复  引用    

#106楼 2008-10-07 15:19 Enmiky[未注册用户]

不错,浏览的人可真不少!   回复  引用    

#107楼 2008-10-07 15:21 Enmiky[未注册用户]

网络不好,多提交了,占你空间了,见谅   回复  引用    

#108楼 2008-10-10 09:35 老醋花生[未注册用户]

提神醒脑,好文。   回复  引用    

#109楼[楼主] 2008-10-10 18:20 Allen Lee      

@Enmiky
@老醋花生
谢谢!
  回复  引用  查看    

#110楼 2009-01-15 09:35 billgates[未注册用户]

虽然从vs2003开始接触
最近用上了vs2008
感觉到有变化
却没能深入的去研究和总结
相当的惭愧
此文总结的很到位
受益匪浅
  回复  引用    

#111楼 2009-05-13 10:33 零八宪章[未注册用户]

好文。
谢谢!
  回复  引用    

#112楼 2009-07-02 22:48 fanscen      

好文,一定要顶个,刚想找几篇高手的c#3.0特性的文章   回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1211520




相关文章:

相关链接: