2011年7月15日 星期五

The C# Programming Language (3rd Edition)


人民幣:RMB 79 元


It is interesting to note that Console.WriteLine() is simply a shortcut for Console.Out.WriteLine.Console.Out is a property that returns an implementation of the System.IO.TextWriter base class designed to output to the console. The previous example could be written equally correctly as follows:

using System;
class Hello
static void Main() {
Console.Out.WriteLine("Hello, World");


C# supports single- and multi-dimensional arrays of any type. Unlike the types listed previously, array types do not have to be declared before they can be used. Instead, array types are constructed by following a type name with square brackets. For example, int[] is a single-dimensional array of int, int[,] is a two-dimensional array of int, and int[][] is a single-dimensional array of single-dimensional arrays of int.


When a value of a value type is converted to type object, an object instance, also called a "box," is allocated to hold the value, and the value is copied into that box. Conversely, when an object reference is cast to a value type, a check is made that the referenced object is a box of the correct value type; if the check succeeds, the value in the box is copied out.

switch語句 原文就有錯誤了,多了一個}。


People need to be careful with the public keyword. public in C# is not equivalent to public in C++! In C++, it means "internal to my compilation unit." In C#, it means what extern meant in C++ (i.e., everybody can call it). This is a huge difference!

protected internal已經證實是一個爭議很大而且有點失敗的選擇。很多人都沒有正確使用這個特性,他們以為protected internal的意思是"只有在這個程序裡繼承的子類才能訪問"。就是說,他們以為是protected 和 internal,而實際上它的意思應該是protected 或者 internal。

protected internal has proven to be a controversial and somewhat unfortunate choice. Many people using this feature incorrectly believe that protected internal means "access is limited to classes derived from this class within this program." That is, they believe it means protected and internal, when, in fact, it means protected or internal.

Were a hypothetical future version of the C# language to provide a syntax for "protected and internal," the question would then be which combination of keywords would have that meaning. I am holding out for either "proternal" or "intected," but I suspect I will have to live with disappointment.

中間有錯字 Point#D 應該是 Point3D 才對


Static fields are per constructed type for a generic type. That is, if you have a

class Stack { public readonly static Stack empty = whatever; ... }


then Stack.empty is a different field than Stack.empty.

public class Color
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);

private byte r, g, b;

public Color(byte r, byte g, byte b) {
this.r = r;
this.g = g;
this.b = b;

Bear:可以參考一下這個例子中的技巧,在static 屬性中利用new 自已的實體方式並回傳出去,以達到靜態呼叫實體這個技巧。


readonly protects the location of the field from being changed outside of the type's constructor but not the value at that location. For example, consider the following type:

public class Names
public static readonly StringBuilder FirstBorn = new
public static readonly StringBuilder SecondBorn = new


Outside of the constructor, directly changing the FirstBorn instance results in a compiler error:

Names.FirstBorn = new StringBuilder("Biff"); // Compile error


However, I am able to accomplish exactly the same results by modifying the StringBuilder instance:

Console.WriteLine(Names.FirstBorn); // Outputs "Biff"


It is for this reason that we strongly recommend that read-only fields be limited to immutable types. Immutable types do not have any publicly exposed setters, such as int, double, or String.


An unfortunate consequence of generic types is that a constructed type may potentially have two methods with identical signatures. For example,

class C { void M(T t){} void M(int t){} ... }


is perfectly legal, but C has two methods M with identical signatures. As we'll see later on, this leads to some interesting scenarios involving overload resolution and explicit interface implementations.


Reference parameters are a slightly different form of "passing by reference." In this case, the reference is to the variable itself, not to some object instance. If that variable happens to contain a value type (as shown in the previous example), that's perfectly legal. The value is not being passed by reference, but rather the variable that holds it is.


A parameter array permits a variable number of arguments to be passed to a method. It is declared with the params modifier. Only the last parameter of a method can be a parameter array, and the type of a parameter array must be a single-dimensional array type. The Write and WriteLine methods of the System.Console class are good examples of parameter array usage. They are declared as follows:

The following Entity class has both static and instance members.

class Entity
static int nextSerialNo;

int serialNo;

public Entity() {
serialNo = nextSerialNo++;

public int GetSerialNo() {
return serialNo;

public static int GetNextSerialNo() {
return nextSerialNo;

public static void SetNextSerialNo(int value) {
nextSerialNo = value;

Each Entity instance contains a serial number (and presumably some other information that is not shown here). The Entity constructor (which is like an instance method) initializes the new instance with the next available serial number. Because the constructor is an instance member, it is permitted to access both the serialNo instance field and the nextSerialNo static field.

The GetNextSerialNo and SetNextSerialNo static methods can access the nextSerialNo static field, but it would be an error for them to directly access the serialNo instance field.

The following example shows the use of the Entity class.

using System;

class Test
static void Main() {

Entity e1 = new Entity();
Entity e2 = new Entity();

Console.WriteLine(e1.GetSerialNo()); // Outputs "1000"
Console.WriteLine(e2.GetSerialNo()); // Outputs "1001"
Console.WriteLine(Entity.GetNextSerialNo()); // Outputs "1002"

Note that the SetNextSerialNo and GetNextSerialNo static methods are invoked on the class, whereas the GetSerialNo instance method is invoked on instances of the class.


A subtle point here is that an overridden virtual method is still considered to be a method of the class that introduced it, and not a method of the class that overrides it. The overload resolution rules in some cases prefer members of more derived types to those in base types; overriding a method does not "move" where that method belongs in this hierarchy.

The method overloading feature can be abused. Generally speaking, it is better to use method overloading only when all of the methods do semantically the same thing. The way many developers on the consuming end think about method overloading is that a single method takes a variety of arguments. In fact, changing the type of a local variable, parameter, or property could cause a different overload to be called. Developers certainly should not see side effects of the decision to use overloading. For users, however, it can be a surprise when methods with the same name do different things. For example, in the early days of the .NET Framework (before version 1 shipped), we had this set of overloads on the string class:

public class String {
public int IndexOf (string value); // Returns the index of value with this instance
public int IndexOf (char value); // Returns the index of value with this instance
public int IndexOf (char [] value); // Returns the first index of any of the
characters in value within the current instance

This last overload caused problems as it does a different thing. For example,

"Joshua,Hannah, Joseph" .IndexOf("Hannah"); // Returns 7


"Joshua,Hannah, Joseph" .IndexOf(new char [] {'H','a','n','n','a,'h;"); // Returns 3

In this case, it would be better to rename the overload that does something different.

public class String {
public int IndexOf (string value); // Returns the index of value within this
public int IndexOf (char value); // Returns the index of value within this
public int IndexOfAny(char [] value); // Returns the first index of any of the
characters in value within the current


Constructors should be lazy! The best practice is to do minimal work in the constructor—that is, to simply capture the arguments for later use. For example, you might capture the name of the file or the path to the database, but don't open those external resources until absolutely necessary. This practice helps to ensure that possibly scarce resources are allocated for the smallest amount of time possible.

A standard "best practice" is to always expose field-like data as properties with getters and setters rather than exposing the field. That way, if you ever want to add functionality to your getter and setter (e.g., logging, data binding, security checking, and so on), you can easily do so without "breaking" any consumer of the code that might rely on the field always being there.


Although in some sense this practice is a violation of another bit of good advice ("Avoid premature generalization"), the new "automatically implemented properties" feature makes it very easy and natural to use properties rather than fields as part of the public interface of a type.


In truth, event is just a keyword that signals C# to restrict the way a delegate can be used, thereby preventing a client from directly invoking an event or hijacking an event by assigning a handler rather than adding a handler. The keyword event makes delegates behave in the way you expect events to behave!


using System;

class Test
static void Main() {
List a = new List();
List b = new List();
Console.WriteLine(a == b); // Outputs "True"
Console.WriteLine(a == b); // Outputs "False"



The first Console.WriteLine outputs TRue because the two lists contain the same number of objects with the same values in the same order. Had List not defined operator ==, the first Console.WriteLine would have output False because a and b reference different List instances.


The takeaway message here is that certain specific data-intensive applications, which would otherwise be gated on heap allocation performance, benefit greatly from using structs. The takeaway message is emphatically not "always use structs because they make your program faster."

The performance benefit here is a tradeoff: Structs can take less time to allocate, but because every assignment of a struct is a value copy, they can take more time to copy than a reference copy would take.


Always remember that it makes little sense to optimize anything other than the slowest thing. If your program is not gated on heap allocations, then pondering whether to use structs or classes for performance reasons is not an effective use of your time. Find the slowest thing, and then optimize it.


With classes, it is possible for two variables to reference the same object and, therefore, possible for operations on one variable to affect the object referenced by the other variable. With structs, each variable has its own copy of the data, and it is not possible for operations on one variable to affect the other. For example, the output produced by the following code fragment depends on whether Point is a class or a struct.

Point a = new Point(10, 10);
Point b = a;
a.x = 20;


If Point is a class, the output is 20 because a and b reference the same object. If Point is a struct, the output is 10 because the assignment of a to b creates a copy of the value, and this copy is unaffected by the subsequent assignment to a.x.


An FxCop rule recommends against multi-dimensional arrays; it's primarily guidance against using multi-dimensional arrays as sparse arrays. If you know that you really are filling in all the elements in the array, multi-dimensional arrays are fine.


In a number of places thus far, the specification notes that a particular local initialization is equivalent to "assign something to a temporary variable, do something to the temporary variable, declare a local variable, and assign the temporary to the local variable." You may be wondering why the specification calls out this seemingly unnecessary indirection. Why not simply say that this is equivalent to

int[] a = new int[3];
a[0] = 1; a[1] = 2; a[2] =3;


This practice is necessary because of definite assignment analysis. We would like to ensure that all local variables are definitely assigned before they are used. In particular, we would like an expression such as object[] arr = {arr}; to be illegal because it appears to use arr before it is definitely assigned. If this were equivalent to

object[] arr = new object[1];
arr[0] = arr;

then that would be legal. But by saying that this expression is equivalent to

object[] temp = new object[1];
temp[0] = arr;
object[] arr = temp;

then it becomes clear that arr is being used before it is assigned.

Enum values can be converted to integral values, and vice versa, using type casts. For example,

int i = (int)Color.Blue; // int i = 2;
Color c = (Color)2; // Color c = Color.Blue;

Bear: 這裡似乎也有翻錯,整型值0應該是整數值0才對。

The default value of any enum type is the integral value zero converted to the enum type. In cases where variables are automatically initialized to a default value, this is the value given to variables of enum types. For the default value of an enum type to be easily available, the literal 0 implicitly converts to any enum type. Thus, the following expression is permitted:

Color c = 0;


This rule implies that you should always ensure that 0 is a valid member of any enum type.

C#自第一版發布以來沒有添加任何新的保留關鍵字。所有要求新關鍵字(yield, select等)的語言新特性都採用了"上下文關鍵字"的手法,也就是它們並非保留字,只是在特定的上下文里有特殊含義而已。這樣'就能保持向後兼容已有的程序了。

C# has added no new reserved keywords since its original release. All the new language features that require new keywords (yield, select, and so on) use "contextual keywords," which are not reserved and have special meaning only in context. This decision helps preserve backward compatibility with existing programs.

Of all the numeric suffixes, m and f are by far the most useful. Without these suffixes, a fractional float or decimal literal cannot be specified without a cast. For example, the following code will not compile, because the literal 1.5 will be parsed as type double:

float x = 1.5; // Error: no implicit conversion from double to float
decimal y = 1.5; // Error: no implicit conversion from double to decimal

Interestingly, the following code does compile, because C# defines an implicit conversion from int to decimal:

decimal z = 123; // Okay: parsed as int, and then implicitly converted to


The d suffix is technically redundant in that the presence of a decimal point does the same job:

Console.WriteLine ((123.0).GetType() == typeof (double)); // True


Bear: 這段話不論是簡體版還是英文版Bear就是看不懂,有沒有人看的懂的可以解釋一下的?

Because a hexadecimal escape sequence can have a variable number of hexadecimal digits, the string literal "\x123" contains a single character with hexadecimal value 123. To create a string containing the character with hexadecimal value 12 followed by the character 3, one could write "\x00123" or "\x12" + "3" instead.

class Test

static void Main() {
object a = "hello";
object b = "hello";
System.Console.WriteLine(a == b);



is true because the two literals refer to the same string instance.

Protected internal (meaning protected or internal), which is selected by including both a protected modifier and an internal modifier in the member declaration. The intuitive meaning of protected internal is "access limited to this program or types derived from the containing class."



There is a difference between the "declared" accessibility and the actual effective accessibility. For example, a method declared as public on a class declared as internal is, for most practical purposes, an internal method.

A good way to think about this issue is to recognize that a public class member is public only to the entities that have access to the class.



Declaring a public member within an internal type might seem pointless, given that the member's visibility will be capped at internal. It can make sense, however, if the public member modifier is interpreted as meaning "having the same visibility as the containing type."

在決定是把一個internal類型的成員聲明為public還是internal的時候,試著問這樣的問題:"如果稍後這個類型被提昇為public,我是不是希望這個成員也變成public? "如果答案是肯定的,你就可以在一開始把這個成員聲明為public。

A good question to ask, in deciding whether to declare a member of an internal type public or internal, is this: "If the type was later promoted to public, would I want this member to become public, too?" If the answer is yes, one could argue for declaring the member as public from the outset.



If you find yourself using new to hide an instance method on the base class, you're almost always going to be disappointed, if for no other reason than a caller can simply cast to the base class to get to the "hidden" method. For example,

class Base { public void F() {} }
class Derived : Base { new public void F() {} }
Derived d = new Derived();
((Base)d).F(); // Base.F not so hidden as you'd like...

You'll be much happier if you pick a new name for the method in the derived class instead.