从第2章到第10章是C#语言的知识内容,在第1章中的程序集(assembly)在后面第11章详述,CIL (公共中间语言)在后面的第15章详述,BCL(基类库)编程在第四部分详述。这是本人关注的几个知识重点。
第9页:倒数第4行:“如果用ildasm.exe(后面章节会说明)”的括号中的内容是指本章的1.15节,在本书第21页。
该工具 ildasm.exe 名称为:MSIL 反汇编程序。
这一章还没有讲C#语言的知识,内容是构建C#应用程序的各种工具。看这章让我想起了在阅读裘宗燕译著《程序设计实践》在译者序中的话: 功能强大的程序开发环境未必能造就出更优秀的程序员
。下面摘抄该书译者序中的一两段:
“在我自己的教学实践中,遇到了许多学生是玩编程环境 的高手,但离程序设计高手却差得太远,他们对算法和数据结构、程序的架构设计和良好的编码的各种要素不太得要领,最熟悉的是排错和单步执行,最拿手的是程序打补丁。”
“一个十行程序就能解决的问题,他们要几十上百行甚至更多,而到最后自己也不知道做得到底对不对,只知道试过一些例子,单步执行无数遍,打了数不清的补丁。可悲的是,以这类活动方式 为编译要义的不只是这些学生,这种情况 不止是校园里,不止是在中国。”
也让我想起了在上海柏盛工作时,老赵用记事本极快的编写C#程序来讲解一个算法的实现。
第50页中的第2行:“而是要进述”中的“进述”应该是“讲述”。
C#中所有数据成员和方法必须全都包含在一个类别定义中。
新建控制台应用程序的项目,名称为 SimpleCSharpApp。而初始代码语句可能如你所想的那样平淡无奇:
using System; using System.Collections.Generic; using System.Text; namespace SimpleCSharpApp { class Program { static void Main(string[] args) { } } }
修改代码成下面的代码语句:
using System; namespace SimpleCSharpApp { class Program { static void Main(string[] args) { //显示简单的消息给用户 Console.WriteLine("Hello World!"); //等待按任意键来关掉 Console.ReadLine(); } } }
Visual Studio 默认在 "Program" 类定义 Main() 方法。类名("Program")也可以取其他的名称。
在这一节中的三段示例代码在《C# 2008 与 .NET 3.5 高级程序设计(第4版)》中Main()方法里后面的“...”均为:
Console.ReadLine();
return -1;
这个章节中第一段第二行:“所考察的概念”是指:C#的语法和 .NET 平台的核心方面。
这个小章节中第一段的第一句: Console类定义了捕获输入和输出的一套方法
这个“类”是type。 它们都被定义成静态的,因此能够从类级别调用。
这个“类”是class。本人认为“能够从类级别调用”按《C# 2008 与 .NET 3.5 高级程序设计(第4版)》中相应的原句应译为:“以类名 Console 为前缀来调用方法名”。
第4版中该章节的示例代码如下:
class Program { static void Main(string[] args) { Console.WriteLine("***** Basic Console I/O *****"); GetUserData(); Console.ReadLine(); } static void GetUserData() { //获得名字和年龄 Console.WriteLine("Please enter your name: "); string userName = Console.ReadLine(); Console.WriteLine("Please enter your age: "); string userAge = Console.ReadLine(); //更改屏显色,只为娱乐开心而已 ConsoleColor prevColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Yellow; //屏显控制台 Console.WriteLine("Hello {0}!You are {1} years old.", userName, userAge); //还原之前的颜色 Console.ForegroundColor = prevColor; } }
程序员可能会忘记采用如init()函数去初始化类对象的事情,或者做了两次(常常会带来同样具有灾难性的后果)。一种更好的方法是让程序员有能力去声明一个明确目的就是去完成对象初始化这样的函数,它将构造起一个给定类型的值。它就被称为构造函数。例如:
--摘自《C++程序设计语言(特别版)》10.2.3 构造函数(本书第202页)
class Date { //...Date(int,int, int); };
下面的代码中粗体部分为默认构造函数的显式写出来了:
using System; class HelloClass { HelloClass() { } public static void Main(string[] args) { HelloClass c1 = new HelloClass(); } }
变量自动设置的默认值与《C# 2008 与 .NET 3.5 高级程序设计(第4版)》中的相应部分内容有出入:
第3点至第5点改为第4版书中的:
下面是用 new 关键字创建基本数据类型变量时良构 C# 代码:
bool b = new bool(); int i = new int(); char c = new char(); DateTime dt = new DateTime(); Console.WriteLine("{0},{1},{2},{3}", b, c, i, dt);
在第62页“局部变量”节中:“简单地做一个初始值即可”与该书第4版相应部分内容有出入,改为:
可以在单行中声明并赋值,也可以将声明和赋值语句分为两行代码:
// dataType varName = initialValue; int localInt = 0; Console.WriteLine(localInt); //也可以将声明和赋值分为两行 string myString; myString = "This is my character data"; Console.WriteLine();
还可以在一行的代码中声明多个相同类型的变量:
bool b1 = true, b2 = false, b3 = b1; Console.WriteLine();
在图3-8中为查看const关键字的常量,下面我们查看去掉const关键字的变量:
.field public static string BestNbaTeam
关键字readonly一节看完若仍存疑问,可查阅MSDN中readonly的代码例子:
public static readonly uint l1 = (uint)DateTime.Now.Ticks;
便会有种释怀的感觉。
值类型和引用类型的比较表(见第83页)
问 题 | 值 类 型 | 引 用 类 型 |
---|---|---|
这个类型分配在哪里? | 分配在栈上 | 分配在托管堆上 |
变量是怎么表示的? | 值类型变量是局部复制 | 引用类型变量指向被分配得实例所占的内存 |
基类型是什么? | 必须继承自System.ValueType | 可以继承自除了System.ValueType以外的任何类型,只要那个类型不是sealed的 |
这个类型能作为其他类型的基类吗? | 不能。值类型是密封的,不能被继承 | 是的。如果这个类型不是密封的,它可以作为其他类型的基类 |
默认的参数传递是什么? | 变量是按值传递的(也就是,一个变量的副本被传入被调用的函数) | 变量是按引用传递(例如,变量的地址传入被调用的函数) |
这个类型能重写System.Object.Finalize()吗? | 不能。值类型不好放在堆上,因此不需要被终结。 | 可以间接地重写 |
我可以为这个类型定义构造函数吗? | 是的,但是默认的构造函数被保留(也就是自定义构造函数必须全部带有参数) | 当然! |
这个类型的变量什么时候消亡? | 当它们越出定义的作用域时。 | 当托管堆被垃圾回收时。 |
另参考:诗剑书生(axman):问题与错误列表