明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

A Comparative Overview of C#中文版(3)

[摘要]10.操作符重載 利用操作符重載機制,程序員可以創(chuàng)建讓人感覺自然的好似簡單類型(如int、long等等)的類。C#實現(xiàn)了一個C++操作符重載的限制版,它可以使諸如這樣的精辟的例子—復數(shù)類操作符重載表...
10.操作符重載
 利用操作符重載機制,程序員可以創(chuàng)建讓人感覺自然的好似簡單類型(如int、long等等)的類。C#實現(xiàn)了一個C++操作符重載的限制版,它可以使諸如這樣的精辟的例子—復數(shù)類操作符重載表現(xiàn)良好。
 在C#中,操作符==是對象類的非虛的(操作符不可以為虛的)方法,它是按引用比較的。當你構(gòu)建一個類時,你可以定義你自己的==操作符。如果你在集合中使用你的類,你應該實現(xiàn)IComparable接口。這個接口有一個叫CompareTo(object)方法,如果“this”大于、小于或等于這個object,它應該相應返回正數(shù)、負數(shù)或0。如果你希望用戶能夠用優(yōu)雅的語法使用你的類,你可以選擇定義<、<=、>=、>方法。數(shù)值類型(int、long等等)實現(xiàn)了IComparable接口。
 下面是一個如何處理等于和比較操作的簡單例子:
public class Score : IComparable
{
int value;
public Score (int score)
{
value = score;
}
public static bool operator == (Score x, Score y)
{
return x.value == y.value;
}
public static bool operator != (Score x, Score y)
{
return x.value != y.value;
}
public int CompareTo (object o)
{
return value - ((Score)o).value;
}
}
Score a = new Score (5);
Score b = new Score (5);
Object c = a;
Object d = b;
按引用比較a和b:
System.Console.WriteLine ((object)a == (object)b; // 結(jié)果為false
【譯注:上句代碼應該為:System.Console.WriteLine ((object)a == (object)b); // 結(jié)果為false】
比較a和b的值:
System.Console.WriteLine (a == b); // 結(jié)果為true
按引用比較c和d:
System.Console.WriteLine (c == d); // 結(jié)果為false
比較c和d的值:
System.Console.WriteLine (((IComparable)c).CompareTo (d) == 0); // 結(jié)果為true
你還可以向Score類添加<、<=、>=、>操作符。C#在編譯期保證邏輯上要成對出現(xiàn)的操作符(!=和==、>和<、>=和<=)必須一起被定義。
11.多態(tài)
 面向?qū)ο蟮恼Z言使用虛方法表達多態(tài)。這就意味著派生類可以有和父類具有同樣簽名的方法,并且父類可以調(diào)用派生類的方法【譯注:此處應該是對象(或?qū)ο笠谩⒅赶驅(qū)ο蟮闹羔槪。在Java中,缺省情況下方法就是虛的。在C#中,必須使用virtual關鍵字才能使方法被父類調(diào)用。
 在C#中,還需要override關鍵字以指明一個方法將重載(或?qū)崿F(xiàn)一個抽象方法)其父類的方法。
Class B//【譯注:應為class B】
{
public virtual void foo () {}
}
Class D : B //【譯注:應為class D : B】
{
public override void foo () {}
}
試圖重載一個非虛的方法將會導致一個編譯時錯誤,除非對該方法加上“new”關鍵字,以指明該方法意欲隱藏父類的方法。
Class N : D //【譯注:應為class N : D】
{
public new void foo () {}
}
N n = new N ();
n.foo(); // 調(diào)用N的foo
((D)n).foo(); // 調(diào)用D的foo
((B)n).foo(); // 調(diào)用D的foo
和C++、Java相比,C#的override關鍵字使得閱讀源代碼時可以清晰地看出哪些方法是重載的。不過,使用虛方法有利有弊。第一個有利點是:避免使用虛方法輕微的提高了執(zhí)行速度。第二點是可以清楚地知道哪些方法會被重載!咀g注:從“不過”至此,這幾句話顯然不合邏輯,但原文就是如此:“However, requiring the use of the virtual method has its pros and cons. The first pro is that is the slightly increased execution speed from avoiding virtual methods. The second pro is to make clear what methods are intended to be overridden.”。我認為,若將被我標為斜體的method改為keyword的話,邏輯上會順暢些。這樣,第一句話就可認為是和Java比,因其方法缺省是虛的,第二句話主要就是和C++比,原因參見我后面的相關注釋】。然而,利也可能是弊。和Java中缺省忽略final修飾符【譯注:在Java中可利用final關鍵字,對方法上鎖,相當于C#/C++中沒有用virtual關鍵字修飾方法/成員函數(shù)的情況】以及C++中缺省忽略virtual修飾符相比,Java中缺省選項【譯注:即虛的】使得你程序略微損失一些效率,而在C++中,它可能妨礙了擴展性,雖然這對基類的實現(xiàn)者來說,是不可預料的。
【譯注:“而在C++中,它可能妨礙了擴展性”這句話或許該這么理解:
class ParentCls
{
public:
 virtual void f(); 
};
/////////////////////////////////////////////////////////////////////////////
class ChildCls : public ParentCls
{
public:
 /*virtual*/ void f();/* 此處不標明為virtual的也是virtual的,但是GrandChildCls并不知道(假定GrandChildCls看不到ParentCls),它不知道應該對該方法overload(當然C++中并overload關鍵字,它是Object Pascal的,這兒再插一句話,overload和override兩詞翻譯都一直都很混亂,Borland官方中文簡體手冊上都翻譯成“重載”)還是override,還是不能碰。即它不知道多態(tài)機制在此是否會發(fā)生作用。或許你會說,試試不就知道啦J */
};
class GrandChildCls : public ChildCls
{
public:
 void f();
};

12.接口
 C#中的接口和Java中的接口差不多,但是有更大的彈性。類可以隨意地顯式實現(xiàn)某個接口:
public interface ITeller
{
void Next ();
}
public interface IIterator
{
void Next ();
}
public class Clark : ITeller, IIterator
{
void ITeller.Next () {}
void IIterator.Next () {}
}
這給實現(xiàn)接口的類帶來了兩個好處。其一,一個類可以實現(xiàn)若干接口而不必擔心命名沖突問題。其二,如果某方法對一般用戶來說沒有用的話,類能夠隱藏該方法。顯式實現(xiàn)的方法的調(diào)用,需把類【譯注:應該是對象】造型轉(zhuǎn)換為接口:
Clark clark = new Clark();
((ITeller)clark).Next();
13.版本處理
 解決版本問題已成為.NET框架一個主要考慮。這些考慮的大多數(shù)都體現(xiàn)于組合體中。在C#中,可在同一個進程里運行同一個組合體的不同版本的能力是令人印象深刻的。
 當代碼的新版本(尤其是.NET庫)被創(chuàng)建時,C#可以防止軟件失敗。C#語言參考里詳細地描述了該問題。我用一個例子簡明扼要地講解如下:
 在Java中,假定我們部署一個稱為D的類,它是從一個通過VM發(fā)布的叫B的類派生下來的。類D有一個叫foo的方法,而它在B發(fā)布時,B還沒有這個方法。后來,對類B做了個升級,現(xiàn)在B包括了一個叫foo的方法,新的VM現(xiàn)在安裝在使用類D的機器上了。現(xiàn)在,使用D的軟件可能會發(fā)生故障了,因為類B的新實現(xiàn)可能會導致一個對D的虛函數(shù)調(diào)用,這就執(zhí)行了一個類B始料未及的動作。【譯注:因Java中方法缺省是虛的】在C#中,類D的foo方法應該聲明為不用override修飾符的(這個真正表達了程序員的意愿),因此,運行時知道讓類D的foo方法隱藏類B的foo方法,而不是重載它。
 引用C#參考手冊的一句有意思的話“C#處理版本問題是通過需要開發(fā)人員明確他們的意圖來實現(xiàn)的”。盡管使用override是一個表達意圖的辦法,但編譯器也能自動生成—通過在編譯時檢查方法是否在執(zhí)行(而不是聲明)一個重載。這就意味著,你仍然能夠擁有象Java一樣的語言(Java不用virtual和override關鍵字),并且仍然能夠正確處理版本問題。
 參見字段修飾符部分。
14.參數(shù)修飾符
(1)ref參數(shù)修飾符
 C#(和Java相比)可以讓你按引用傳遞參數(shù)。描述這一點的最明顯的例子是通用交換方法。不象C++,不但是聲明時,調(diào)用時也要加上ref指示符:【譯注:不要誤會這句話,C++中當然是沒有ref關鍵字】
public class Test
{
public static void Main ()
{
int a = 1;
int b = 2;
swap (ref a, ref b);
}
public static void swap (ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
}
(2)out參數(shù)修飾符
out關鍵字是對ref參數(shù)修飾符的自然補充。Ref修飾符要求參數(shù)在傳入方法之前必須被賦值。而out修飾符則明確當方法返回時需顯式給參數(shù)賦值,。
(3)params參數(shù)修飾符
 params修飾符可被加在方法的最后的參數(shù)上,方法將接受任意數(shù)量的指定類型的參數(shù)【譯注:在一個方法聲明中,只允許一個params性質(zhì)的參數(shù)】。例如:
public class Test
{
public static void Main ()
{
Console.WriteLine (add (1, 2, 3, 4).ToString());
}
public static int add (params int[] array)
{
 int sum = 0;
 foreach (int i in array)
 sum += i;
 return sum;
}
}
【作者注:學習Java時一個非常令人詫異的事是發(fā)現(xiàn)Java不能按引用傳遞參數(shù),盡管不久以后,你很少會再想要這個功能,并且寫代碼時也不需要它了。當我第一次閱讀C#規(guī)范的時候,我常想,“他們干嗎把加上這個功能,沒有它我也能寫代碼”。經(jīng)過反省以后,我意識到這其實并不是說明某些功能是否有用的問題,更多是說明了沒有它你就另需別的