2011年7月5日 星期二

Beginning C# 2008 Objects

Beginning C# 2008 Objects中文版--概念到代碼(第2版)


Bear在這裡買的
amazon的參考
-----------------------------------------------------------
作者:(美)帕默//芭克|譯者:薛瑩//任鴻//程文俊
出版社:清華大學
ISBN:9787302223474
出版日期:2010/06/01
裝幀:
頁數:569
人民幣:RMB 78 元
-----------------------------------------------------------

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
本書第II部份(第8章到第12章)對象建模101(Object Modeling 101)講的是UML建構過程,
Bear只是隨手翻過並無刻意去閱讀,因此也沒有摘列出讀書心得。
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

P.77~78(原文P.82~83)
然而,良好的編程習慣是在方法中僅包含一個return語句,並使用本地變量獲取最終返回結果。只有一個return語句能夠更簡單地跟蹤複雜方法的執行流程。

A method body is permitted to include more than one return statement if desired. For an example of a method containing multiple return statements, let’s look once again at the IsHonorsStudent method discussed previously:
bool IsHonorsStudent()
{
if (gpa >= 3.5)
{
return true; // first return statement
}
else
{
return false; // second return statement
}
}

Good programming practice, however, is to have only one return statement in a method and to use a locally declared variable to capture the result that is to ultimately be returned. Having only a single return statement can make it easier to follow the execution flow of a complicated method. Although it is not a particularly complicated method, here is an alternative version of the IsHonorsStudent method that observes this practice:
bool IsHonorsStudent()
{
// Declare a local variable to keep track of the outcome;
// arbitrarily initialize it to false.
bool honors = false;
if (gpa >= 3.5)
{
honors = true;
}
else
{
honors = false;
}
// We now have a single return statement at the end of our method.
return honors;
}

P.96(原文P.82~83)
Pascal命名法(首字母大寫)用於所有類和方法的命名,無論其可訪問性如何。它還用於公有字段的命名。
Camel命名法(首字母小寫)用於非公有字段的命名。

Pascal casing (uppercase starting letter) is used for all class and method names regardless of their accessibility. It’s also used for the names of public fields. Camel casing (lowercase starting letter) is used for the names of nonpublic fields.

P.97(原文P.104)

If you want more information, consult the section “Statements, Expressions, and Operators” from the “C# Programming Guide” at the MSDN web site.

P.99(原文P.106)

將字段名的第一個字母大寫並在前面放入Get或Set
當字段是bool類型時,推薦使用動詞Is代替Get來命名get方法

Note that we devise the names for both types of method by capitalizing the first letter of the field name and sticking either Get or Set in front of it. There is one exception to this method naming convention: when a field is of type bool, it’s recommended that we name the “get” method starting with the verb Is instead of with Get. The “set” method for a bool field would still follow the standard naming convention.

P.112(原文P.119)

不過,導致連鎖反應的原因是修改了類的公有成員-準確而言,是公有的屬性頭。只要將更改限於類的私有成員(私有字段和存取器代碼體),而不去更改公有方法/屬性頭,連鎖反應就不會發生。

But again, this ripple effect is due to the fact that we changed a public member of our class—a public property header, to be precise. As long as we restrict our changes to private members of a class—private field and accessor code bodies, but not public method/property header(s)— ripple effects are not an issue.

P.112(原文P.120)

然而,最好的辦法是調用類的存取器,即使在類自身的方法中,而不僅因為"我能夠"就直接訪問字段。原因是,因為字段目前可能很簡單,但無法保證它以後不會變得複雜。
However, it’s considered a best practice to get into the habit of invoking a class’s accessors, when available, even from within that class’s own methods, instead of directly accessing fields “just because we can,” as a convenience. The reason for this is as follows: just because a field may be simple today, there’s no guarantee that it won’t become complicated down the road.

P.137(原文P.148~149)
在類方法內部使用get存取器是最佳實踐,在第4章曾討論過:它能充份利用值的檢查功能或get存取器所能提供的其它操作
public void Print()
{
// Print the values of all of the fields that the Student class
// knows about; note use of get accessors.
Console.WriteLine("Student Name: " + Name + "\n" +
"Student No.: " + StudentId + "\n" +
"Major Field: " + MajorField + "\n" +
"GPA: " + Gpa);
}

// This example accesses fields directly by name, bypassing the
// associated properties; this approach is discouraged.
Console.WriteLine("Student Name: " + name + "\n" +
"Student No.: " + studentId + "\n" +
"Major Field: " + majorField + "\n" +
"GPA: " + gpa);

Using get accessors within a class’s own methods reflects a “best practice” discussion that we had in Chapter 4; it allows us to take advantage of any value checking or other operations that the get accessor may provide.

P.139(原文P.151)
派生類E(GraduateStudent)再次重寫該方法,不但輸出從Student類繼承的字段(其中也有從Person類繼承的),還會輸出GraduateStudent自已添加的字段。

Derived class E (GraduateStudent) overrides this method again, to print not only the fields inherited from Student (which include those inherited from Person) but also those that were added by the GraduateStudent class itself.

P.141(原文P.153)
如果Student類從Person類繼承的Print方法頭為不帶參數的public void Print(),那麼Student類就不能更改方法頭,例如,讓它接受1個實參:public void Print(int noOfCopies)。這樣做會創建一個完全不同的方法,在C#語言中這種特性稱為重載(overloading)。

Bear: 用錯了virtual >> override的技術的話,會造成overload

Don’t Attempt to Change a Method Header
For example, if the Print method inherited by the Student class from the Person class has the header public void Print(), where the method takes no arguments, then the Student class can’t change this method to require an argument, say, public void Print(int noOfCopies). To do so is to create a different method entirely, due to another C# language feature known as overloading, discussed next.

P.174(原文P.189)
這種方法引入了兩個新的類/抽象--TranscriptEntry和Transcript--比第一種方法稍微複雜一些,第一種方法只引入了TranscriptEntry作為抽象。同樣,第二種方法更加接近於真實的對象範例,因為Student類不需要關心Transcript的外在表現和內在管理,這些細節隱藏在Transcript類的內部,這是它們應該存在的地方。

This “take two” approach of introducing two new classes/abstractions—TranscriptEntry and Transcript—is a bit more sophisticated than the first approach, in which we introduced TranscriptEntry only as an abstraction. Also, this second approach is “truer” to the object paradigm, because the Student class needn’t be complicated by the details of how Transcripts are represented or managed internally—those details are hidden inside of the Transcript class, as they should be.

P.199(原文P.216)
在這種情況下,基類名必須始終位於列表的最前方,後面跟上將要實現的所有接口的名稱。

A class may simultaneously extend a single base class and implement one or more interfaces, as follows:
public class Professor : Person, ITeacher, IAdministrator {...}
Under such circumstances, the name of the base class must always come first in the list, followed by the names of all interfaces to be implemented.

P.200(原文P.216)
換句話說,編譯器將冒號後的第一個條目看作是基類,而將列表中的其它條目看作是接口

In other words, the compiler will consider only the first entry after the colon as a base class, and everything else in the list is assumed to be an interface.

接口不可以被實例化

Interfaces can’t be instantiated.

P.310(原文P.342~343)
using SRS;
using ObjectStart;
using System;
public class Example
{
static void Main()
{
// We are still qualifying Course wherever we use it in
// this program...
SRS.Course math = new SRS.Course();
ObjectStart.Course english = new ObjectStart.Course();
//...but simple name string is OK because of the using
// directive at the top of the code listing.
string name = "Dinesh Prabhu";
math.Professor = name;
// Ditto for Student.
Student s = new Student();
// etc.
}
}

P.316(原文P.349)
如果在字符串開始的雙引號前加上@,則字符串就能從源代碼文件中讀入,允許字符串跨多行並能保持所有換行、跳格、反斜杠等字符不變

If we precede the opening double quote mark of a string literal with @, the literal will be read verbatim from the source code file, allowing the literal to span multiple lines and leaving all newlines, tabs, backslashes, and so on intact.

P.317(原文P.350)
原文及翻譯都錯,字尾應無s

String str = "Tom Servo";
Console.WriteLine("The first character is " + str[0]);

This code snippet would generate the following output:

The first character is Ts

P.329(原文P.362)
public static void Resize(ref T[] array, int newSize)該方法用於重新設置一維數組的大小。嚴格來說,實際發生了如下操作:創建指定大小的新數組,將舊數組的元素複製到新數組中,然後用新數組取代舊數組。

Bear: Array的Resize是重新建立新的Array而非修改原有的Array喔

public static void Resize(ref T[] array, int newSize): This method is used to resize a one-dimensional array. Strictly speaking, what takes place is a new array is created with the specified size, the elements of the old array are copied into the new one, and the old array is replaced with the new one.

P.339(原文P.373)
var關鍵字只能用於局部變量中,而不能用於在類級別上聲明的字段。數組的初始化不能使用隱式輸入的局部變量。

The var keyword can only be applied to local variables and can’t be used on fields declared at the class level. Implicitly typed local variables can’t be used with the array initializer.

P.339~340(原文P.373~374)
Main方法有以下4種不同的形式

static void Main()
static int Main()
static void Main(string[] args)
static int Main(string[] args)

P.340(原文P.374)
注意,這4種Main方法都沒有包含訪問修飾符(如public)。即使包含訪問修飾符,也會在運行時忽略它們。C#的慣例是在Main方法中忽略訪問修飾符

Note that none of the four Main method headers includes an access modifier (for example, public). If we include one, the runtime will ignore it. The C# convention is to omit the access modifier from the Main method.

P.345(原文P.378~379)

public string GetFacultyAdvisorName()
{
// Note: since some of our constructors initialize
// facultyAdvisor with a Professor object, and others do not,
// we cannot assume that the field has been initialized with a
// Professor reference when this method is invoked. We
// check to make sure that the facultyAdvisor field
// is NOT null before proceeding.
if (facultyAdvisor != null)
{
return facultyAdvisor.Name;
}
else
{
return "TBD";
}
}

P.347(原文P.380~381)
using System;
public class Student
{
private string name;
private string id;
private Transcript transcript;
// Constructors.
// This version takes one argument.
public Student(string n)
{
name = n;
transcript = new Transcript();
// do some other complicated things...
}
// This version takes two arguments. We want to reuse the logic
// from the preceding constructor without having to repeat the
// same code in both constructors. We can invoke the
// one-argument constructor from this two-argument version by
// using the "this" keyword in the manner shown below:
public Student(string n, string id)
: this(n)
{
// Now, we can go on to do other "extra" things that this
// version of the constructor needs to take care of.
this.id = id;
}
// etc.
}

By using the syntax : this(n) in this fashion, it’s as if we’ve written the code for the second constructor as follows—but without having to duplicate code from the first constructor:
public Student(string n, string id)
{
// Duplicate the code from the first constructor...
name = n;
transcript = new Transcript();
// do some other complicated things...
//...then go on to do other "extra" things that this version
// of the constructor needs to take care of.
this.id = id;
}

Thus, by using the : this(...) syntax to reuse constructor code from one version to another, if the logic of the first constructor changes down the road, the second constructor will also benefit.

P.349(原文P.384)
這和我們的身體器官類似,例如,心臟是身體的一部份,但我們無法直接看到或解摸到它

It’s analogous to an internal organ in our body; for example, our heart is part of our physical body, but we can’t see or access it directly.

P.352(原文P.387)
前面已討論過,Person類現在只能識別一個構造函數--帶有兩個參數的構造函數--因為Person類預設的無參數構造函數將被刪除。

Bear: 當類別無預設建構子時,.NET會自動在內部幫你生一個預設無參數的建構子,但當你自已手動加上任何建構子時,自動生成的建議子就會自動消失。

We know from an earlier discussion that the Person class now recognizes only one constructor signature—one that takes two arguments—because the default parameterless constructor for Person has been eliminated.

P.361(原文P.396)

關於方法隱藏的最後注意事項

1. 和重寫一樣,在新的派生/隱藏的方法中可使用base關鍵字調用原始基類版本的隱藏方法。
2. 派生類的隱藏方法可以有不同的返回類型,這些返迴類型不同於基類的返回類型。
3. 抽象方法不能被隱藏。

Final Notes Regarding Method Hiding
A few final points:
1. The original base class version of a hidden method can be called from within the “new” derived/hidden method using the base keyword, just as when overriding.
2. A derived class’s “hidden” method can have a different return type than the base class version it is hiding.
3. An abstract method can’t be hidden.

P.365(原文P.400)

為何要用抽象方法來重寫非抽象方法?答案是強迫Person類的派生類實現該類特定的ToString方法。也就是說,我們不希望Person類的派生類太懶,只是繼承Object類中ToString方法的預設行為--我們希望能有效抹去其具體實現。

Why might we want to override a nonabstract method with an abstract one? The answer is to force derived classes of Person to implement their own class-specific versions of the ToString method. That is, we don’t want any of the future classes derived from Person to be “lazy” by simply inheriting the default behavior of the Object class’s ToString method—we want to effectively “erase” the details of how this behavior is carried out.

P.369(原文P.404)

注意,如果想要引用屬於某個顯式命名的名稱空間中的類名,而且沒有在代碼中包括合適的using語句,則必須在使用typeof時使用類的完全限定名稱。

Note that if we want to refer to the name of a class that belongs to an explicitly named namespace, and we haven’t included the appropriate using statement with our code, we must fully qualify the class name when using typeof:
// Assume that Bar is a class in the Foo namespace.
if (x.GetType() == typeOf(Foo.Bar) {...}

P.389(原文P.452)

Bear: 這裡有問題,我看它明明前面的例子跟本都是用public,那來的protected access?

Note that the Student class’s ToString method is accessing the values of the Name and Id properties that were declared in the Person class. This operation is permitted because the get accessors for those properties were given protected access, and Student is a derived class of Person.