msdn 访谈录之C#编程二

程序员天地

Robert Hess和Jeffrey Richter(著名的编程作家、专栏作家和咨询专家)的谈话。


ROBERT HESS: 欢迎回来。我们正要涉及到有关C#编程方面的问题。为了有助于我们理解这些问题,我邀请我的好朋友Jeffery Richter到这里来。Jeffery恰好是一名撰写了很多编程书籍的程序员,他最新的一本书为Programming Server Side Applications for Windows 2000。现在您也是一位咨询专家并且拥有自己的公司Wintellect,是吗?

JEFFREY RICHTER: Wintellect。

ROBERT HESS: 我猜您有一个网站吧?

 

JEFFREY RICHTER:有,Wintellect.com。我们专门从事培训、调试和广告。

ROBERT HESS: 好了,我了解到您最近做了不少有关C#的工作。

 

JEFFREY RICHTER: 是的,至今已一年有余了,我花了很大的精力一直专攻C#的编程。

ROBERT HESS:已经有一年了?我想我们才刚发布了C#。

JEFFREY RICHTER:是的,可我一直在圈内,在Microsoft的圈内,如果您愿意的话。我自己在第42楼安置了一个小小的办公室,并在那里从事C#的研究和有关.NET这方面的工作,到现在已经一年多了。

ROBERT HESS: 这样微软就会对您有所帮助,因为您并不是微软的职员……

 

JEFFREY RICHTER: 对。

ROBERT HESS:他们只是帮助您的把C#当成一种语言理解,那么您就可以写出更多象这样的书?

JEFFREY RICHTER:是的,他们希望我写更多的书,我得到了帮助,发现了bug,出席了类似的一些规范会议,并与人们交流,因此我觉得学到了很多的东西,而不只是写书,而事实在某种程度上也对C#做出了贡献。所以我可以告诉您,当最初开始时,我感兴趣的第一个东西就是这种新的语言,我将用它来写所有的代码,我知道这些代码是为可以预见的未来写的,让我们暂且不提。我具有非常深厚的C、C++背景,在阅读与C#相关文档和编程参考等资料一个星期之后,我就觉得已经相当精通C#了。并且在一周之内,我能够真正地写出一些有用的东西。

 

ROBERT HESS:仅仅一周之后。

JEFFREY RICHTER:是的,仅仅一周之后。因为它和C++非常类似,您知道,那里的大括号是相同的,返回值是相同的,参数是相同的,许多东西都是相同的。

ROBERT HESS:当继续使用对象、析构函数、构造函数、双冒号(::)等这些老掉牙的东西时,您似乎就要失去他们所拥有有的某些奇特的命名习惯,对吗?

JEFFREY RICHTER:是的是的,双冒号(::)都被点号(.)代替,箭头号(->)也被点号代替,这样就大大地简化了该语言。因而对于我来说实在是太容易啦,而且它还具有时效性,我仍不得不回过头去查看该语言参考资料,或许查找如何重载运算符,或者某些很平常的东西,要知道,当我编程时,极少做一些模糊不清的事。而现在大多数东西对我来说是再自然不过的了。事实上要解决的只是流程问题。

ROBERT HESS:既然您从事这项工作已经一年多了,那么您注意到了在这段时间里这种语言自身的演变吗?是否它们今天仍然与一年以前的十分相同?

JEFFREY RICHTER:我认为十分相同。但肯定存在着一些小技巧(tweak),在beta测试阶段确实存在着这些回应,存在着许多非确定性的析构函数(non deterministic destructor)、对象的析构(destruction of objects)等类似的东西。因此,基类库已经增加了一个iDisposable接口,我想它将会出现在beta 2.0版中,而不是在beta 1.0版中。同时C#已增加了一些新的语言结构,以帮助你获得与对象的确定性析构(deterministic destruction of objects)关系密切的东西。所以我要说,微软已经十分在意人们对该语言的评价了,并且他们还企图在其中加入新的东西以做出回应。我同样了解到,将来在1.0版之后,他们计划要增加泛型(generics),这有点类似C++中的模板,而我可以肯定,为了支持这些性能,C#就要发展。实际上当处于公共语言运行库(common language runtime)之中时,所有的语言都能用到泛型。

 

ROBERT HESS:因为它们是其中的一部份,又因其是公共语言运行库,所以它们有权使用所有的那些功能。那么您认为,C#作为一种语言总的来说究竟怎么样?

JEFFREY RICHTER:嗯,正如我所说的,C#与C++非常相似,所以我很快便熟悉了。它非常非常的干净,我要说它是非常干净的。我出身于C++背景,尤其是作为一个Windows C++程序员。ANSII拥有C++规范,微软为了展示Windows中的功能,就想在C++中保留一些技巧,并且使这些技巧看起来有点像C++中的贵族,可它们从来就没有真正地达到要求。而微软仍陆续增加__try、  __finally 和 __declspec等类似的东西。

ROBERT HESS:这就是您正在谈论的C#。

JEFFREY RICHTER:对,当然还有C++。因此,这种语言确实有点恐怖,过了一会儿您还是不会完全弄明白,就如const的用法,当声明一个指针或者是一个常量指针时,星号(*)究竟应放在它的前面,还是放在后面?您将无法断定这些修饰符到底应放在该行的那个位置。我总是需要查资料。因此在C#中,由于微软在设计时已经预先向ECMA(欧洲计算机制造商协会)做出了要求标准化的提议,所以它实在很干净,例如,没有什么是以下滑杠开始的。当然,由于本来在.NET runtime中就没有真正的指针,所以在您的代码中,从头到尾都不会能见到*号和&号等此类修饰符。这样当考虑它时,看起来干净,真的觉得很爽。

 

ROBERT HESS:难道您不觉得缺少什么吗?我的意思是,当我在用C编程时,喜欢运用指针解决问题,对指针重新分类,利用指针算法等老掉牙的东西,您就会从中获得极大的乐趣。难道您在用C#时就不怀念它吗?

JEFFREY RICHTER:嗯,我不得不承认,我自己总是有些喜新厌旧,但有时也有点念它。当然总的来说,有了C#和.NET framework,您就可以始终与其它语言进行交互操作(interoperate out),因而如果真的必须那样做的话,我便用C++而不是C#编程了。C#也确实提供了一种不安全的关键词(unsafe keyword),这样一来,您就可以创建一个方法并且说,这是不安全的,您有权使用指针并对内存进行直接操作。尽管如此,我还是从未亲自体验过。至于编码时获得的乐趣,.NET framework和基本OS类库提供了大量的特性,它们使编程变得有趣了。因此,当我不能保留虚拟内存并稀疏地提交,也不能在.NET framework中利用内存映象文件进行工作时,至少不能直接进行时,也可以通过交互操作完成,仍然还有其它类似serialization和web服务等东西,它们有利于创作出真正有价值的应用程序,真正强大而丰富的内涵。

ROBERT HESS:如今在您的培训班里,您正在教授和灌输这样的东西,您还在办C#的培训班吗?

JEFFREY RICHTER:是的,事实上刚好这一周,我给第一个C#编程班上课,当时班里有两个Visual Basic程序员,他们根本就不是面向对象的程序员,而我也没有真正地给他们介绍过C#语言,因为我把重点放在公共语言运行库和基类库方面,有关C#的内容想稍后再讲。但是,这两个VB程序员在上机实习时,对C#上手很快,几乎没有遇到什么麻烦,而且竟然能用其进行开发,效率也高。我十分惊讶!

ROBERT HESS:其中的原因是由于在C#中,您使用name.name.name.name,而不是name、->、name.name、-> name.*、*、()、&等老掉牙的东西……

JEFFREY RICHTER: 确实这样。

ROBERT HESS:这些在VB中都不会用到。

JEFFREY RICHTER:正确。

ROBERT HESS:所以格式看来相当一致。

JEFFREY RICHTER:对,相当一致。当然,他们用大括号{}而不是begin和end,这可能使有些人不适应。但我认为,他们最多花不到5分钟的时间就可以克服它,而且更多产。

RROBERT HESS:那么以一个公司的立场,假如一个公司聘请您去开设一个C#培训班,因此我得去发现他们是否开始考虑把公司的一些成果移植到C#,这就是您建议他们要做的事吗?或者您认为他们应处于哪一个阶段?

JEFFREY RICHTER:嗯,当然它取决于,首先他们必须决定是否要采用.NET framework作为开发平台。我认为这非常有价值,对于我来说毫无问题,那是我真正向往的平台。如果您正在开发.NET framework的应用软件,正在编写新的代码,在我看来会不费吹灰之力。 C#上手实在是很容易,它是一种生机勃勃的语言,使用正确的方法您会非常多产的。我个人也相信大量的VB程序员,VB6.0程序员,将会转向C#而不是VB7.0。

ROBERT HESS:那为什么?

JEFFREY RICHTER:因为我认为C#揭示了公共语言运行库(common language runtime)之中的更多的特性,使您对代码及其所表达的方法具有更多一点的控制权。您将更直接地与runtime对话,runtime赋予了您更多的权力。

ROBERT HESS:当然,我们本身谁都不是VB程序员,所以将明确地在C基础之上发展。

JEFFREY RICHTER: 您是对的。

ROBERT HESS:所以这正是它物有所值之处,我们有点偏离正题了。那么作为一种语言,您喜欢C#的哪些方面呢?是更简单、更彻底(clean)的编程吗?

 

JEFFREY RICHTER: 嗯,主要是去掉了无用的东西。 譬如, 嗯, C#不允许您把参数作为常量(const)声明,并且您不能拥有一个const的实体方法,而在C++中则可以。我知道某些人会认为那样会真的丧失语言的特性,但事实在C++中,const总是会被无情地抛弃,这样您就能在自己的代码中为所欲为了。由于C#实在是不允许您使用const,所以它又彻底又易于理解。现在,我想我应该说:对于我,.NET frameworks真正有趣的东西就是公共语言运行库。它定义对象如何运转,或如何创建类型,以及是什么定义了这些类型的行为。这样您就拥有了一个基类库,当然它是一个巨大的类库,它让您有权使用大量的东西,所以即使您愿意,也不必再三重写每一样东西了。您选择语言是您个人的事情,而我选择了C#是由于它是真正优秀的高阶语言,它让我能与framework对话。但在某种程度上,运用.NET runtime和基类库真正最佳的语言应该是中间语言(immediate language)汇编语言。

ROBERT HESS:哈!谈到汇编语言啦?

 

JEFFREY RICHTER:是的,谈到汇编语言了。我的意思是,它使您完全有权访问平台的底层,但在汇编语言的环境中效率会很低,有这么多的程序您必须一行一行地写。所以,C#语言高出了一个层次。而在C#中的有些性能并不是很常用,因此象Anders 这样的C#设计者已决定不必将其公开了。在某些情况下,为了访问C#没有提供的runtime功能,我可能会求助于另外一种语言。但总的来说,C#是最高层的语言,它允许我在这样的环境中按自己的需求解决大量的问题,而且效率极高。

 

ROBERT HESS:并不是所有的问题,而仅仅只是大部份?

JEFFREY RICHTER:不,极少会出现这种情况:我还需要访问某些东西,而C#却不让访问。这是另外一方面,我只是认为大家非常容易忘却的是,当您想要访问.NET的一些功能而C#或某些语言却不提供给您时,可以转到别的语言。只需编码创建这个方法,可能是一个静态方法(static method),类中的静态方法,用APL或COBOL或凡是您选择的语言,或许派生,然后用某些语言实现实体方法,而这种语言可能真的让您访问某些底层功能。因此,我认为这是一个功能非常强大的范例,以前我从未真正地领会过要选择最佳的语言去完成工作。

 

ROBERT HESS:好了,我打赌各位观众可能想要看一些C#代码的例子,以便能理解我们谈论到的一些问题。您有例子示范给我们看吗?

 

JEFFREY RICHTER:有。我确实的带来了一个源代码文件,里面有一些例子,能勉勉强强地应付,在节目结束后,我会给您的。欢迎您把它上传到网站上,以让大家可以下载。所以在这里,如果你样喜欢的话,我首先要示范的是:在C#中,每一个方法必须位于类中。没有全局方法,也没有位于类之外的变量,所以每一样东西都会被限定在一定的范围内。
using System;

 

class App {

   public static void Main () {

      Console.WriteLine("Hello World");

   }

}

这是一个必须保留的hello world程序,非常简单。在程序里,有一个类叫App,在这个类里,我拥有自己的一个Main方法,并且Main是一个静态方法,因为它必须从外面调用。我们不必拥有App的一个实例就可以调用Main。在我这个例子里,Main返回void,并且没有接受参数。简单地在Main的内部,它调用了Console.WriteLine,在显示器上面显示出"Hello World"。所以这是您可以写的、能学到相关概念的最小程序了。

 

ROBERT HESS:在C#中Main仍然是一个保留的方法吗?就象在C++中?

JEFFREY RICHTER: Main是默认的,它具有大写字母M,小写字母a-i-n ,因为C#是字母大小写敏感的语言,象C++ 而不象VB 和.NET 。所以当编译器编译代码时,将寻找一个叫做Main的静态方法,然后再使用它。然而有一个编译器的命令行,它可以覆盖掉Main并选取其中不同的一个。顺便说一下,事实上这是一门很有用的技巧。一些人把多个Main放到一个单个的应用程序里,以便进行组测试,当编译时,可以设置不同的开关执行不同的Main,以便测试特定的组件。

ROBERT HESS:绝妙的技巧。您也使用象argv、 argc这样的参数,默认地传递给Main函数吗?

using System;

 

class App {

   public static void Main (string[] args) {

      Console.WriteLine("Hello World");

   }

}

 

JEFFREY RICHTER:是,随您的便。在这里,我将当场修改这些代码,也就是说,string是一个字符串数组,args 按我在幻灯片中播放的定义。顺便地,这个args是什么呢?是一个数据类型!它是一个指向字符串的指针,或者是一个指向字符串的引用。说到指针,您只见过带*号的,但args确实是一个指针。当Main被调用之前,启动代码早已解析命令行,并且创建一个字符串数组,接着把指针传入该数组。象对args.length类似的调用使我可以解决一些问题,该调用会返回数组的length属性,此属性含有数组元素的个数,然后我正好可以利用一个正常的for语句进行循环,或者可以用C#的for each,特殊的for each语句用于快速的循环。

 

ROBERT HESS:很新颖,这是在C或C++中所没有的。

JEFFREY RICHTER:正确。而我确实也有演示的代码,我找到了。

static void ArrayDemo() {

   // 声明一个指向数组的引用

   Int32[] ia; // 默认值为 null

   ia = new Int32[100];

   ia = new Int32[] { 1, 2, 3, 4, 5 };

   .

   .

   .

这是一个具有数组的代码的例子,所以我会略为提一下。在这个例子里,首先声明一个指向Int32s数组的引用,随意取一个"ia"用于整数数组。它只不过是一个指针,具有32位(bit)或64位值,如果它们仍在64位系统上运行,总是会被初始化为null,引用总是被初始化为null直到明确地设置它为止。下面一行,我随意new(构造)了一个有100个Int32值的数组。new返回一个引用,接着我把这个引用存到"ia"变量中。下一行只不过演示了另外一种构造的方式,这里我又new了一个Int32s数组,这种专门的C#句法以一个左大括号开始,后面跟着数组的元素,当然元素之间要用逗号分开,然后是一个右括号。当您第一次见到这种句法时,会觉得它有点笨拙。这只不过是new的另外一种用法,当然它可以推算出元素的个数。


ROBERT HESS: 而这只不过是预定义了值:

   .

   .

   .

   // 显示数组的内容

   foreach (Int32 x in ia)

      Console.Write("{0} ", x);

 

 

   //使用多维数组

   StringBuilder[,] sa = new StringBuilder[10][5];

   for (int x = 0; x < 10; x++) {

      for (int y = 0; y < 5; y++) {

         sa[x][y] = new StringBuilder(10);

      }

   }

 

   // 使用数组的数组(jagged arrays)

   Int32 numPolygons = 3;

   Point[][] polygons = new Point[numPolygons][];

   polygons[0] = new Point[3]  { ... };

   polygons[1] = new Point[5]  { ... };

   polygons[2] = new Point[10] { ... };

}

 

JEFFREY RICHTER:是的,很正确。这就是foreach,它出现在代码的第一行。"foreach"是C#句法,我肯定所有的.NET语言都会提供此句法,它是一个极其通用的编程典范,用这种方式,就可以遍历集合里的元素。因此,这里的foreach Int32 x中,"x"是一个变量,Int32当然是一种类型,接着我把引用赋予了数组。foreach将会自动推算出数组中有多少个元素,并且每当循环到Console.Write时,就会显示出元素的值,然后再移向下一个元素。


ROBERT HESS:而"for (i=0, i<ia.length, i++)"也做同样的工作,但如果您想要遍历所有的元素的话,这种方式有些笨拙以至难于遵循,所以一直持续不断地做十分相同的事情,我想会更加容易。


JEFFREY RICHTER:对,精辟。尽管如此,我会给您一点提示,由于foreach有点酷,也十分精巧,因此省去了大量的编码。它也另外做一些有关类型转换(casting)的工作,这对您同样也有好处。所以一般来说,当我写一个循环时,我通常会以foreach开始,然后当我继续编码时,有时经常地,我随后认识到我需要一个迭代器(iterator),需要一个从0到实际数字的X。是的,我必须知道哪一个元素号。所以我终止了重写这个循环,相当频繁……


ROBERT HESS: 噢,真的吗?


JEFFREY RICHTER: 是真的。

 

ROBERT HESS: 当作一个标准的For循环?

 

JEFFREY RICHTER:对,当作一个标准的For循环。因此有时到了最后,它所做工作比我当初想象的还要多。使用foreach是相当常见的,有了它实在是很爽。


ROBERT HESS:我猜您本来也应当在那里放置一个计数器,不过这会完全使foreach不起作用。


JEFFREY RICHTER: 是的,很正确。

 

ROBERT HESS:那么,您认为C#还另外具有什么样很酷特性,以让观众说,好,这就是我要选的语言?


JEFFREY RICHTER:嗯,正如Anders在前面指出,C#是完全基于组件的,在那里具有事件,具有接口,具有属性,它们都是一等公民,所以没有下滑杠,没有下滑杠属性等任何类似的东西。出身于C#的人应当熟悉异常处理,因为遇到错误时,就调用在基类库中的framework里的错误处理程序。因此我在屏幕上写了一小块代码,以示范如何进行适当的错误处理。我具有一个try语块,再强调一下,您应注意在try这个单词的前面没有下滑杠,因为在C#语言中它位于第一阶层。我new一个文件流对象,这是打开磁盘里的文件的一种方式。而在双引号里,我给出了我们希望打开的文件的路径名。

using System;

using System.IO;

 

public class App {

   public static void Main () {

      FileStream fs = null;

      try {

         fs = new FileStream(@"C:/NotThere.txt", FileMode.Open);

      }

      catch (Exception e) {

         Console.WriteLine(e.Message);

      }

      finally {

         if (fs != null) fs.Close();

      }

   }

}

 


ROBERT HESS:等等,那是一个错误,是吗?

 

JEFFREY RICHTER:不,这正是我要指出的。因为C#有一个非常酷的特性,可以给字符串加上一个@符号的前缀,使我们转用原义字符串(verbatim  string,即真正的字符串,不加任何转义符),这里只允许使用单反斜杠“/”而不是双反斜杠“//”。而长路径实在是一种十分常见的C++编程错误,人们以反斜杠代替双反斜杠,文件就不能正确地打开。在这种情况下应用加上"/n",意思是要换行。所以,这实在是一个巧妙的特性。不象一个file stream,因为人们熟悉Win32的CreateFile函数,当该函数无法打开一个文件时就会返回无效的句柄值,或返回-1意味着失败。在.NET framework中,当我企图打开一个不存在的文件时,就会引发一个异常,所以我在这里设置了一个catch语块,设法捕获到异常,这是一个非常简单的catch语块,只把信息输出屏幕,看看可能做了些什么,接着我又设置了一个finally语块,在这里的代码要确保能执行,因此假如我在try语块中有很多行真正涉及到文件操作的代码,在打开文件之后,finally语块就会执行并在最后明确地关闭文件。这实在是一种很巧妙的特性,Win32甚至是C++也不曾拥有,它能够使try,catch和finally浑然一体,真正算起来,这种操作我们以前从未遇见过。


ROBERT HESS:我认为当应用程序变得越来越复杂时,人们在其中进行错误处理是相当重要的,当企图创建文件或进行类似的操作时,出错的机会可能会很多。尤其是使用其他人的对象和类似的东西时。
    那么,这是不是意味着在编写C#的应用程序时,您必须保证函数和方法都能正确地设置异常并抛出一个异常,以便人们可以捕获它?
 

JEFFREY RICHTER:嗯,绝对如此。良好的编程典范规定:当编写一个函数时,必须验证所有传递进来的参数,如果任何一个参数不合乎要求,就应当明确地引发一个异常,而在基类库中定义有大量的异常类,所以可以轻而易举地使用其中的一个。但是您同样也有能力定义自己的异常类,或许,要查找数据库中的、顾客(customer),却好象没有发现他们的名字,故可以创建自己的customer异常,并在代码里的某个地方引发它。

ROBERT HESS:或许会用类似customer的名字作为损坏的customer名……


JEFFREY RICHTER:是的,大概这样。如果它是"Robert",就是你一直想要引发的异常。

ROBERT HESS:那么,您认为C#作为一种编程语言将如何发展?当您的客户参加培训时您对他们有什么点拨,他们对此又有什么想法?

 

JEFFREY RICHTER:嗯,我真的认为它将获得巨大的动力。我说过,去年我一直专门用C#编程,偶尔也用C++,但现在却很少用了,而我相信许多VB程序员也将会转向此语言,因为C#更适合公共语言运行库。所以,我真的认为它将获得巨大的动力,并且真正得到重用。在我的培训班里,似乎每个人都喜欢它,事实上一些人说他们参加这个培训班,只是由于这个班开设了C#编程的课,但很快他们就高兴地发现课程也涵盖了framework和类库。

ROBERT HESS:那么,当谈到.NET framework和类库时,您认为它们怎么样,以及它们是怎样帮助应用程序开发的?

 

JEFFREY RICHTER:我认为,这个平台表现很出色。我使用整个平台已经一年了,并且我最近一直在为微软开发一个项目,以展示微软的许多技术。我和另外一个家伙一起工作,他的名字叫Tom,我们要在早上碰头,要在电子白板上继续讨论,接着要…… 这里就是我们今天将要补充说明的性能,我们又要讨论一会儿,我们要表示,这就是当天结束时我们的目标,通常在午饭之前我们要全部完工。我们总是超额地完成了任务。

 

ROBERT HESS:您认为C#和.NET的结合有助于完成工作吗?


JEFFREY RICHTER: 噢,当然。毫无疑问,因为所有的测试都已完成。所有的测试——我们如何公开这个东西,我们能不能使这成为一个方法,能不能把它放在DLL里,能不能使其成变COM 对象,我们应拥有什么类型的接口。所有的这些问题涉及到您如何把这些连接起来并传递指针,保持连接以便可以同步,所以您就可以通过保持和其他人同步来通知他们,所有这些论点都刚刚被引进该平台。因此,自始至终地,我们愿意工作一个小时,我们要完成某项工作,我们会……,然后我们又要坐回去并开始增加其它的东西。我们的生产率如何,确实令人难于置信,而且也同样充满着乐趣。我们确实增加了惊人的图形图像库和alpha混色(blending)以及所有类型的东西,这些以前我们从未处理过alpha混色此类东西。我曾经从事过图形图像的工作,但已经过了好多年了。而利用相应名字空间中的system.drawing语句,我们就能够构造这些图像并对它们进行覆盖和alpha混色,然后又从我们的web服务器返回这些图像给在任何机器上运行的任一客户,甚至不必是一台Windows机器。


ROBERT HESS:我想这带来了有利的选择。迄今为止,我们一直在谈论用C#和.NET framework等进行应用程序的开发,并且我了解到您原来就是一个货真价实的应用程序设计师,编写Windows应用程序和标准的GUI程序。令人意外的是web出现了,因此每个人都想到编写web应用程序,或编写运行在浏览器内部基于HTML的应用程序。但现在以一句话对您的产品进行概括,您正在谈到具有这种alpha合成标准的Windows图形应用程序,也谈到了访问web并以相应的格式返回给其它系统。那么象您我这样的Win32应用程序开发者,对传统的应用程序开发环境以及新的web应用程序与.NET的混合有什么看法?

 

JEFFREY RICHTER:嗯,我实际上在做的就是这种特别的事情,它不是Win32图形应用程序,而是一个web窗体(form),随意一个web窗体。
ROBERT HESS:那么它甚至也不是一个传统的Windows应用程序吗?它听起来很象啊。
JEFFREY RICHTER:嗯,它真正是什么?实际上它比传统的Win32程序具有更复杂的体系。它实际是一个web服务,并且我认为它是第一批公用微软web服务(public Microsoft web services)之一,是免费的,所以我会给出URL地址。因此谁都可到那里去摆弄摆弄,这个地址是teraserver.Microsoft.net。
ROBERT HESS:噢,我会把这个地址放在本记录稿的后面,以便大家点击访问。

JEFFREY RICHTER:那里有许多微软技术的广告宣传,其中包括Windows 2000 Datacenter、SQL 2000、IIS、ASP.net、.NET frameworks、web services和web forms。所在的资料都在那个网站上。有一个具有图像信息的teraserver web服务,它显示立体地形图和常规像片里的图像和标题。而且我们也有一个人口普查(census)服务,所以可以到那里输入纬度、经度等,便得到相应的城市名以及生活在该地区的人口。我们还有地标(landmark)服务,给出一个以经纬度标定的矩形区,就可以找到该地区范围内的医院和学校。因此,它们是三个单独的web 服务。它们本来可以由不同的公司实现,但实际上都是由我们实现的。接着我们编写了一个web窗体应用程序,它本来可以由任何公司编写,但这次又由我们编写,以便弄清概念,它向这三个不同的web服务发出信息,接着从teraserver获取标题信息,从landmark服务器获取地标信息,然后我们就能够把这些信息载入地图。

 

ROBERT HESS:使用alpha混色。

JEFFREY RICHTER:嗯,对,使用alpha混色。于是,这些信息被送回web窗体,送回运行在任何机器上的客户。我们甚至可以增加这样的功能,当鼠标移到某东西上方时,提示工具将会显现并告诉您该网页上相应的学校名和医院名。此范例功能之强大,简直令人无法相信。事实上客户可以是运行任何操作系统的任何机器,并且我们在服务器端利用Windows 2000的GDI+性能处理alpha混色,以及此类高级图形操作,不过我们只把位图(bit map)送回给客户,我再次认为,其功能之强大、生产率之高,简直令人信难于置信。而且我也了解到许多应用正在朝这个方向发展。

ROBERT HESS:所以您真的很喜欢web应用程序的整个web模型。
JEFFREY RICHTER: 喜欢。

 ROBERT HESS:即使您是一个传统的Windows应用程序开发者。
JEFFREY RICHTER: 是的。

ROBERT HESS:您现在已横下心来要朝这个方向发展了。

 

JEFFREY RICHTER:是的,我已下决心了。程序要能在任何地方运行,并在服务器上进行工作。所有的这些便构成了所谓的分布式系统(distributedness),服务器可以位于三台不同的机器,噢,维护所有的这些资料的SQL Server还可以是另一台机器,web 窗体服务器也位于不同的机器,并且还可以被不同的公司细调以便随意使用这些材料,他们觉得这些材料适合于生成内容丰富的应用程序,而这些程序运行在能被internet访问到的任何地方。这简直令人难于置信,确实难于置信!

ROBERT HESS:某些迹象告诉我,所有的这些东西给您留下了现象。

JEFFREY RICHTER:是的,有点。

ROBERT HESS:那么,对于观众中跃跃欲试的开发人员,他们想要投身于C#,并要开始编写一些.NET应用程序,在他们跨出第一步之前,需要真正地了解什么?您认为最后还有什么要强调的?

 

JEFFREY RICHTER:我认为,这些开发人员即将面临的一个最大问题就是,他们必须认识到是C#语言揭示了runtime和基类库中的性能,或许假以时日他们会从经验中学到。而许多人将会关注C#,也可能他们会试一试,或关注其它的.NET语言,也有可能会企图做一些不被这些语言所支持的事,接着当然认为这是不可能的。例如:在C#中,所有的数组默认都是基于0的,是以0索引(下标)开始的。但是公共语言运行库支持数组有任何的下边界和上边界。在基类库中构造了一个数组,它具有所设定的上下边界。但是C#自然不提供这些功能。因此,您必须去学习,随着时间的推移,就会了解它是什么,很多时候您或许可以使用其它语言,或者去访问语言的底层系统,语言是位于runtime顶端的,由于某些原因,设计者不让我们去访问底层系统。

ROBERT HESS:似乎就是这样,通过理解runtime底层的所有性能,然后您就可以把这些性能映射(map)给您目前正在使用的任何语言,以便了解它们是否提供给您所需要的功能。例如,我写网页时总是用纯粹的HTML编写,因为我知道它的具体功能是什么。但是假如我必须用FrontPage写,我知道FrontPage有它自己的格式(mindset),关系到网页的显示,并且我知道它能给我提供什么,不能提供什么。偶尔我也不得不转回纯粹的HTML并按这种方式增加某些东西或其它工具,这似乎是同样的事情。

JEFFREY RICHTER:有时在C#中也有这些功能,但却以不同的名字出现,例如,在公式语言库中,虚拟函数被称为family 。于是要在C#中创建一个虚拟函数,就会用protected 限定。对,或不用protected,但是在C#中的protected是等价于公共语言运行库中的family的。噢,搞混了。看看,连我自己也糊涂了。

ROBERT HESS:因此基本的思路听起来好象就是要去理解您正在使用的工具,以及它们在.NET framework底层的运行情况。好了,非常感谢Jeffery,又与您交谈我感到非常荣幸,以后我会找一个时间再次邀请您回来参加这个“show”节目的。

JEFFREY RICHTER:好,我很乐意,谢谢。

ROBERT HESS:这就是程序员Jeffery对C#和.NET framework的看法。他提供给你们一些好资料,以让你们了解更新的开发领域。他讲到了很多的URL地址和源代码例子以及类似的资料。我保证把它们放在本记录稿的后面,所以请继续观看其余的“show”节目,看看还有什么内容。
……(略去与C#无关的谈话)



 

 结束语

 


ROBERT HESS:谢谢您参加另一期的MSDN Show。这一次我们讨论了用C#编程的问题。

 

ERICA WIECHERS:在下一期的MSDN Show节目里,我们将谈论SOAP以及它是如何被整合到.NET编程体系的。

 

ROBERT HESS: 到那时,我们再在网上见面。

 

 

更多资料的链接

 

Microsoft C#资料:

C#综述和介绍(Overview and Introduction to C#,http://msdn.microsoft.com/vstudio/nextgen/technology/csharpintro.asp)

 

C#语言规范(C# Language Specificationhttp://spectre/test/library/default.asp?URL=/library/dotnet/csspec/vclrfcsharpspec_Start.htm

 

MSDN之声:深入C#专栏(MSDN Voices: Deep C# columnhttp://msdn.microsoft.com/voices/deepc.asp

    一个定期的专栏,在这里Bobby Schmidt分享他使用C#的观点和见识。

 

MSDN .NET开发者中心(MSDN Developer Center for .NEThttp://msdn.microsoft.com/net/

     提供更多有关.NET技术的开发资料。

 

C#新闻组(C# Newsgroupnews://msnews.microsoft.com/microsoft.public.dotnet.languages.csharp

与正在学习使用C#的人互相讨论、互相请教。

 

有关Jeffrey Richter谈话的资料:

代码范例(Sample Code:地址不详)

书: Programming Applications for Microsoft Windows

     Programming Server-Side Applications for Windows

(和Jason Clark合写)

Wintellecthttp://www.wintellect.com/,)

Jeffrey 的培训和咨询公司。

TerraServer.NEThttp://terraserver.microsoft.net/

Jeffrey帮助编写的mapping服务。

Jeffrey Richter的主页(http://www.jeffreyrichter.com/)

 

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论
内容简介 · · · · · · 这是一本经典的Windows核心编程指南,从第1版到第5版,引领着数十万程序员走入Windows开发阵营,培养了大批精英。 作为Windows开发人员的必备参考,本书是为打算理解Windows的C和C++程序员精心设计的。第5版全面覆盖Windows XP,Windows Vista和Windows Server 2008中的170个新增函数和Windows特性。书中还讲解了Windows系统如何使用这些特性,我们开发的应用程序又如何充分使用这些特性,如何自行创建新的特性。... 作者简介 · · · · · · Jeffrey Richter是一位在全球享有盛誉的技术作家,尤其在Windows/.NET领域有着杰出的贡献。他的第一本Windows著作Windows 3: A Developer's Guide大获好评,从而声名远扬。后,他又推出了经典著作《Windows 高级编程指南》和《Windows核心编程》。如今这两本书早已成为Windows程序设计领域的颠峰作,培育了几代软件开发设计人员。他的每一本新作问世,我们都有理由相信这是一本巨著,我们想要的一切尽在其中。Jeffery 是Wintellect公司的创始人一,也是MSDN杂志.NET专栏的特邀编辑。现在他正领导开发该公司的.NET程序设计课程,向大众推广.NET技术。因为他自1999年开始就参与了微软.NET框架开发组的咨询工作,与这些一线人员一起经历了.NET的孕育与诞生,所以他对.NET思想的领悟、对.NET的细节熟稔,是其他任何作家难以企及的。他是.NET著作领域中当无愧的一面旗帜。 Christophe Nasarre是Business Objects的软件架构师和开发部门领导,该公司致力于帮助其他企业更好地专注于其主营业务,通过商业智能方案来提升决策能力和业绩。他为Addison-Wesley,APress和Microsoft Press出版的许多图书担任过技术审校,此外还是MSDN Magazine的撰稿人。 目录 · · · · · · 第1部分 必备知识 第1章 错误处理 1.1 定义自己的错误代码 1.2 ErrorShow示例程序 第2章 字符和字符串处理 2.1 字符编码 2.2 ANSI字符和Unicode字符与字符串数据类型 2.3 Windows中的Unicode函数和ANSI函数 2.4 C运行库中的Unicode函数和ANSI函数 2.5 C运行库中的安全字符串函数 2.5.1 初识新的安全字符串函数 2.5.2 在处理字符串时如何获得更多控制 2.5.3 Windows字符串函数 2.6 为何要用Unicode 2.7 推荐的字符和字符串处理方式 2.8 Unicode与ANSI字符串转换 2.8.1 导出ANSI和Unicode DLL函数 2.8.2 判断文本是ANSI还是Unicode 第3章 内核对象 3.1 何为内核对象 3.1.1 使用计数 3.1.2 内核对象的安全性 3.2 进程内核对象句柄表 3.2.1 创建一个内核对象 3.2.2 关闭内核对象 3.3 跨进程边界共享内核对象 3.3.1 使用对象句柄继承 3.3.2 改变句柄的标志 3.3.3 为对象命名 3.3.4 终端服务命名空间 3.3.5 专有命名空间 3.3.5 复制对象句柄 第Ⅱ部分 工作机制 第4章 进程 4.1 编写第一个Windows应用程序 4.1.1 进程实例句柄 4.1.2 进程前一个实例的句柄 4.1.3 进程的命令行 4.1.4 进程的环境变量 4.1.5 进程的关联性 4.1.6 进程的错误模式 4.1.7 进程当前所在的驱动器和目录 4.1.8 进程的当前目录 4.1.9 系统版本 4.2 CreateProcess函数 4.2.1 pszApplicationName和pszCommandLine参数 4.2.2 psaProcess,psaThread和bInheritHandles参数 4.2.3 fdwCreate参数 4.2.4 pvEnvironment参数 4.2.5 pszCurDir参数 4.2.6 psiStartInfo参数 4.2.7 ppiProcInfo参数 4.3 终止进程 4.3.1 主线程的入口点函数返回 4.3.2 ExitProcess函数 4.3.3 TerminateProcess函数 4.3.4 当进程中的所有线程终止时 4.3.5 当进程终止运行时 4.4 子进程 4.5 管理员以标准用户权限运行时 4.5.1 自动提升进程的权限 4.5.2 手动提升进程的权限 4.5.3 何为当前权限上下文 4.5.4 枚举系统中正在运行的进程 4.5.5 Process Information示例程序 第5章 作业 5.1 对作业中的进程施加限制 5.2 将进程放入作业中 5.3 终止作业中的所有线程查询作业统计信息 5.4 作业通知 5.6 Job Lab示例程序 第6章 线程基础 6.1 何时创建线程 6.2 何时不应该创建线程 6.3 编写第一个线程函数 6.4 CreateThread函数 6.4.1 psa参数 6.4.2 cbStackSize参数 6.4.3 pfnStartAddr和pvParam参数 6.4.4 dwCreateFlags 6.4.5 pdwThreadID7 6.5 终止运行线程 6.5.1 线程函数返回 6.5.2 ExitThread函数 6.5.3 TerminateThread函数 6.5.4 进程终止运行时 6.5.5 线程终止运行时 6.6 线程内幕 6.7 C/C++运行库注意事项 6.7.1 用_beginthreadex而不要用CreateThread创建线程 6.7.2 绝对不应该调用的C/C++运行库函数 6.8 了解自己的身份 6.8.1 将伪句柄转换为真正的句柄 第7章 线程调度、优先级和关联性 7.1 线程的挂起和恢复 7.2 进程的挂起和恢复 7.3 睡眠 7.4 切换到另一个线程 7.5 在超线程CPU上切换到另一个线程 7.6 线程的执行时间 7.7 在实际上下文中谈CONTEXT结构 7.8 线程优先级 7.9 从抽象角度看优先级 7.10 优先级编程 7.10.1 动态提升线程优先级 7.10.2 为前台进程微调调度程序 7.10.3 调度I/O请求优先级 7.10.4 Scheduling Lab 示例程序 7.11 关联性 第8章 用户模式下的线程同步 8.1 原子访问:Interlocked系列函数 8.2 高速缓存行 8.3 高级线程同步需要避免使用的一种方法 8.4 关键段 8.4.1 关键段:细节 8.4.2 关键段和旋转锁 8.4.3 关键段和错误处理 8.5 Slim读/写锁 8.6 条件变量 8.6.1 Queue示例程序 8.6.2 在停止线程时的死锁问题 8.6.3 一些有用的窍门和技巧 第9章 用内核对象进行线程同步 9.1 等待函数 9.2 等待成功所引起的副作用 9.3 事件内核对象 9.4 可等待的计时器内核对象 9.4.1 让可等待的计时器添加APC调用 9.4.2 计时器的剩余问题 9.5 信号量内核对象 9.6 互斥量内核对象 9.6.1 遗弃问题 9.6.2 互斥量与关键段的比较 9.6.3 Queue示例程序 9.7 线程同步对象速查表 9.8 其他的线程同步函数 9.8.1 异步设备I/O 9.8.2 WaitForInputIdle函数 9.8.3 MsgWaitForMultipleObjects(Ex)函数 9.8.4 WaitForDebugEvent函数 9.8.5 SignalObjectAndWait函数 9.8.6 使用等待链遍历API来检测死锁 第10章 同步设备I/O与异步设备I/O 10.1 打开和关闭设备细看CreateFile函数 10.2 使用文件设备 10.2.1 取得文件的大小 10.2.2 设置文件指针的位置 10.2.3 设置文件尾 10.3 执行同步设备I/O 10.3.1 将数据刷新至设备 10.3.2 同步I/O的取消 10.4 异步设备I/O基础 10.4.1 OVERLAPPED结构 10.4.2 异步设备I/O的注意事项 10.4.3 取消队列中的设备I/O请求 10.5 接收I/O请求完成通知 10.5.1 触发设备内核对象 10.5.2 触发事件内核对象 10.5.3 可提醒I/O 10.5.4 I/O完成端口 10.5.5 模拟已完成的I/O请求 第11章 Windows线程池 11.1 情形1:以异步方式调用函数 11.1.1 显式地控制工作项 11.1.2 Batch示例程序 11.2 情形2:每隔一段时间调用一个函数 11.3 情形3:在内核对象触发时调用一个函数 11.4 情形4:在异步I/O请求完成时调用一个函数 11.5 回调函数的终止操作 11.5.1 对线程池进行定制 11.5.2 得体地销毁线程池:清理组 第12章 纤程 第Ⅲ部分 内存管理 第13章 Windows内存体系结构 13.1 进程的虚拟地址空间 13.2 虚拟地址空间的分区 13.2.1 空指针赋值分区 13.2.2 用户模式分区 13.3 地址空间中的区域 13.4 给区域调拨物理存储器 13.5 物理存储器和页交换文件 13.6 页面保护属性 13.6.1 写时复制 13.6.2 一些特殊的访问保护属性标志 13.7 实例分析 13.8 数据对齐的重要性 第14章 探索虚拟内存 14.1 系统信息 14.2 虚拟内存状态 14.3 NUMA机器中的内存管理 14.4 确定地址空间的状态 14.4.1 VMQuery函数 14.4.2 示例程序:虚拟内存映射 第15章 在应用程序中使用虚拟内存 15.1 预订地址空间区域 15.2 给区域调拨物理存储器 15.3 同时预订和调拨物理存储器 15.4 何时调拨物理存储器 15.5 撤销调拨物理存储器及释放区 15.5.1 何时撤销调拨物理存储器 15.5.2 虚拟内存分配示例程序 15.6 改变保护属性 15.7 重置物理存储器的内容 15.8 地址窗口扩展 第16章 线程栈 16.1 C/C++运行库的栈检查函数 16.2 Summation示例程序 第17章 内存映射文件 17.1 映射到内存的可执行文件和DLL 17.1.1 同一个可执行文件或DLL的多个实例不会共享静态数据 17.1.2 在同一个可执行文件或DLL的多个实例间共享静态数据 17.1.3 Application Instances示例程序 17.2 映射到内存的数据文件 17.2.1 方法1:一个文件,一块缓存 17.2.2 方法2:两个文件,一块缓存 17.2.3 方法3:一个文件,两块缓存 17.2.4 方法4:一个文件,零个缓存 17.3 使用内存映射文件 17.3.1 第1步:创建或打开文件内核对象 17.3.2 第2步:创建文件映射内核对象 17.3.3 第3步:将文件的数据映射到进程的地址空间 17.3.4 第4步:从进程的地址空间撤销对文件数据的映射 17.3.5 第5步和第6步:关闭文件映射对象和文件对象 17.6 File Reverse示例程序 17.7 用内存映射文件来处理大文件 17.8 内存映射文件和一致性 17.9 给内存映射文件指定基地址 17.10 内存映射文件的实现细节 第18章 堆 18.1 进程的默认堆 18.2 为什么要创建额外的堆 18.2.1 对组件进行保护 18.2.2 更有效的内存管理 18.2.3 使内存访问局部化 18.2.4 避免线程同步的开销 18.2.5 快速释放 18.3 如何创建额外的堆 18.3.1 从堆中分配内存块 18.3.2 调整内存块的大小 18.3.3 获得内存块的大小 18.3.4 释放内存块 18.3.5 销毁堆 18.3.6 在C++中使用堆 18.4 其他堆函数 第Ⅳ部分 动态链接库 第19章 DLL基础 19.1 DLL和进程的地址空间 19.2 纵观全局 19.2.1 构建DLL模块 19.2.2 构建可执行模块 19.2.3 运行可执行模块 第20章 DLL高级技术 20.1 DLL模块的显式载入和符号链接 20.1.1 显式地载入DLL模块 20.1.2 显式地卸载DLL模块 20.1.3 显式地链接到导出符号 20.2 DLL的入口点函数 20.2.1 DLL_PROCESS_ATTACH通知 20.2.2 DLL_PROCESS_DETACH通知 20.2.3 DLL_THREAD_ATTACH通知 20.2.4 DLL_THREAD_DETACH通知 20.2.5 DllMain的序列化调用 20.2.6 DllMain和C/C++运行库 20.3 延迟载入DLL 20.4 函数转发器 20.5 已知的DLL 20.6 DLL重定向 20.7 模块的基地址重定位 20.8 模块的绑定 第21章 线程局部存储区 21.1 动态TLS 21.2 静态TLS0 第22章 DLL注入和API拦截 22.1 DLL注入的一个例子 22.2 使用注册表来注入DLL 22.3 使用Windows挂钩来注入DLL 22.4 使用远程线程来注入DLL 22.4.1 Inject Library示例程序 22.4.2 Image Walk DLL 22.5 使用木马DLL来注入DLL 22.6 把DLL作为调试器来注入 22.7 使用CreateProcess来注入代码 22.8 API拦截的一个例子9 22.8.1 通过覆盖代码来拦截API0 22.8.2 通过修改模块的导入段来拦截API 22.8.3 Last MessageBox Info示例程序 第Ⅴ部分 结构化异常处理 第23章 终止处理程序 第24章 异常处理程序与软件异常 24.1 通过实例理解异常过滤程序和异常处理程序 24.1.1 Funcmeister1函数 24.1.2 Funcmeister2函数 24.2 EXCEPTION_EXECUTE_HANDLER1 24.2.1 一些有用的例子 24.2.2 全局展开 24.2.3 停止全局展开 24.3 EXCEPTION_CONTINUE_EXECUTION 24.4 EXCEPTION_CONTINUE_SEARCH0 24.5 GetExceptionCode2 24.6 GetExceptionInformation6 24.7 软件异常 第25章 未处理异常、向量化异常处理与C++异常 25.1 UnhandledExceptionFilter函数详解 25.2 即时调试 25.3 电子表格示例程序 25.4 向量化异常和继续处理程序 25.5 C++异常与结构化异常的比较 25.6 异常与调试器 第26章 错误报告与应用程序恢复 26.1 Windows错误报告控制台 26.2 可编程的Windows错误报告 26.3 对进程中所有的问题报告进行定制 26.4 问题报告的创建与定制 26.4.1 创建一个自定义的问题报告 26.4.2 设置报告参数:WerReportSetParameter 26.4.3 将小型转储文件放入报告:WerReportAddDump8 26.4.4 将任意文件放入报告:WerReportAddFile9 26.4.5 修改对话框文本:WerReportSetUIOption0 26.4.6 提交错误报告:WerReportSubmit0 26.4.7 关闭问题报告:WerReportCloseHandle 26.4.8 Customized WER示例程序 26.5 应用程序的自动重启与恢复 26.5.1 应用程序的自动重启 26.5.2 对应用程序恢复的支持 第Ⅵ部分 附录A 构建环境 附录B 消息处理宏、子控件宏和API宏 索引

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

rainbow

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值