六月婷婷综合激情-六月婷婷综合-六月婷婷在线观看-六月婷婷在线-亚洲黄色在线网站-亚洲黄色在线观看网站

明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

Top Ten Traps in C# for C++ Programmers中文版(轉(zhuǎn))(2)

[摘要]陷阱六.虛方法必須被顯式重載在C#中,如果程序員決定重載一個(gè)虛方法,他(她)必須顯式使用override關(guān)鍵字。讓我們考察一下這樣做的好處。假定公司A寫了一個(gè)Window類,公司B購(gòu)買了公司A的Wi...
陷阱六.虛方法必須被顯式重載

在C#中,如果程序員決定重載一個(gè)虛方法,他(她)必須顯式使用override關(guān)鍵字。

讓我們考察一下這樣做的好處。假定公司A寫了一個(gè)Window類,公司B購(gòu)買了公司A的Window類的一個(gè)拷貝作為基類。公司B的程序員從中派生【譯注:原文為...using...,從下文來(lái)看,顯然是“派生”之意。事實(shí)上,使用類的方式還有“組合”(也有說(shuō)為“嵌入”或“包容”(COM語(yǔ)義)等等),后者不存在下文所描述的問題】出ListBox類和RadioButton類。公司B的程序員不知道或不能控制Window類的設(shè)計(jì),包括公司A將來(lái)對(duì)Window類可能做的修改。

現(xiàn)在假定公司B的程序員決定為L(zhǎng)istBox類加入一個(gè)Sort方法:

public class ListBox : Window

{

public virtual void Sort() {}

}

這是沒有問題的—直到公司A的Window類作者發(fā)布了Window類的版本2,公司A的程序員向Window類也加入了一個(gè)public的Sort方法:

public class Window

{

public virtual void Sort() {}

}

在C++中,Window類新的虛方法Sort將會(huì)作為L(zhǎng)istBox虛方法的基類方法。當(dāng)你試圖調(diào)用Window的Sort時(shí),實(shí)際上調(diào)用的是ListBox的Sort。C#中虛方法【譯注:原文寫成virtual function】永遠(yuǎn)被認(rèn)為是虛擬調(diào)度的根。這就是說(shuō),只要C#找到了一個(gè)虛方法,它就不會(huì)再沿著繼承層次進(jìn)一步尋找了,如果一個(gè)新的Sort虛方法被引入Window,ListBox的運(yùn)行時(shí)行為不會(huì)被改變。當(dāng)ListBox再次被編譯時(shí),編譯器會(huì)發(fā)出如下警告:

"\class1.cs(54,24): warning CS0114: 'ListBox.Sort()' hides inherited member 'Window.Sort()'.

如果要使當(dāng)前成員重載實(shí)現(xiàn),可加入override關(guān)鍵字。否則,加上new關(guān)鍵字。

如果想要移去這個(gè)警告,程序員必須明確指明他的意圖。可以將ListBox的Sort方法標(biāo)為new,以指明它不是對(duì)Window的虛方法的重載:

public class ListBox : Window

{

public new virtual void Sort() {}

}

這樣編譯器就不會(huì)再警告。另一方面,如果程序員想重載Window的方法,只要顯式加上override關(guān)鍵字即可。

陷阱七:不可以在頭部進(jìn)行初始化

C#里的初始化不同于C++。假定你有一個(gè)類Person,它有一個(gè)私有成員變量age;一個(gè)派生類Employee,它有一個(gè)私有成員變量salaryLeverl。在C++中,你可以在Employee構(gòu)造器的成員初始化列表部分初始化salaryLevel:

Employee::Employee(int theAge, int theSalaryLevel):

Person(theAge) // 初始化基類

salaryLevel(theSalaryLevel) // 初始化成員變量

{

// 構(gòu)造器體

}

在C#中,這個(gè)構(gòu)造器是非法的。盡管你仍可以如此初始化基類,但對(duì)成員變量的初始化將導(dǎo)致一個(gè)編譯時(shí)錯(cuò)誤。你可以在成員變量聲明處對(duì)其賦初始值:

Class Employee : public Person

{

// 在這兒聲明

private salaryLevel = 3; //初始化

}

【譯注:以上代碼有誤LC#中,正確寫法如下:

class Employee: Person

{

private int salaryLevel = 3;

}



你不需要在每一個(gè)類聲明的后面都加上一個(gè)分號(hào)。每一個(gè)成員都必須要有顯式的訪問級(jí)別聲明。

陷阱8.不能把布爾值轉(zhuǎn)換為整型值

在C#中,布爾值(true、false)不同于整型值。因此,不能這么寫:

if ( someFuncWhichReturnsAValue() )//【譯注:假定這個(gè)方法不返回布爾值】

也不能指望如果someFuncWhichReturnsAValue返回一個(gè)0它將等于false,否則為true。一個(gè)好消息是誤用賦值操作符而不是相等操作符的老毛病不會(huì)再犯了。因此,如果這么寫:

if ( x = 5 )

將會(huì)得到一個(gè)編譯時(shí)錯(cuò)誤,因?yàn)閤 = 5的結(jié)果為5,而它不是布爾值。

【譯注:以下是C++里一不小心會(huì)犯的邏輯錯(cuò)誤,編譯器不會(huì)有任何提示L運(yùn)行得很順暢,不過(guò)結(jié)果并不是你想要的:

C++:

#include "stdafx.h"

int main(int argc, char* argv[])

{

int n = 0;

if (n = 1)//編譯器啥都沒說(shuō)L一般推薦寫為1 == n,萬(wàn)一寫成1 = n編譯器都不同意J

{

printf("1\n");

}

else

{

printf("0\n");

}

return 0;

}

以上運(yùn)行結(jié)果為1,這未必是你想要的。

C#:

using System;

public class RyTestBoolApp

{

public static void Main()

{

int n = 0;

if (n = 1)//編譯器不同意J無(wú)法將int轉(zhuǎn)換成bool

{

Console.WriteLine("1");

}

else

{

Console.WriteLine("0");

}

}

}

但如果是這種情況:

bool b = false;

if (b = true)

...

不管是C++還是C#都沒招L



【譯注:C++程序員一般是喜歡這種自由的寫法:

if (MyRef)

if (MyInt)

但在C#里,必須寫成:

if (MyRef != null)//或if (null != MyRef)

if (MyInt != 0)//或if (0 != MyInt)

等。



陷阱九.switch語(yǔ)句不可“貫穿”【譯注:即fall through,Beta2的聯(lián)機(jī)文檔就是如此譯法】

在C#中,如果在case語(yǔ)句里有代碼的話,那它就不可“貫穿”到下一句。因此,盡管下面代碼在C++里合法,但在C#中則不然:

switch (i)

{

case 4:

CallFuncOne();

case 5: // 錯(cuò)誤,不可以“貫穿”

CallSomeFunc();

}

為了達(dá)到這個(gè)目的,需要顯式地使用goto語(yǔ)句:

switch (i)

{

case 4:

CallFuncOne();

goto case 5;

case 5:

CallSomeFunc();

}

如果case語(yǔ)句沒做任何事(里面沒有代碼)就可以“貫穿”:

switch (i)

{

case 4: // 可以“貫穿”

case 5: // 可以“貫穿”

case 6:

CallSomeFunc();

}

【譯注:以下是使用switch的完整例子,它還說(shuō)明了switch語(yǔ)句的參數(shù)類型可以是字符串,此例同時(shí)還演示了屬性的使用方法。

using System;

class RySwitchTest

{

public RySwitchTest(string AStr)

{

this.StrProperty = AStr;

}

protected string StrField;

public string StrProperty

{

get

{

return this.StrField;

}

set

{

this.StrField = value;

}

}

public void SwitchStrProperty()

{

switch (this.StrProperty)

{

case ("ry01"):

Console.WriteLine("ry01");

break;

case ("ry02"):

Console.WriteLine("ry02");

break;//如果這一行注釋掉,編譯器會(huì)報(bào)控制不能從一個(gè)case標(biāo)簽(case "ry02":)貫穿到另一個(gè)標(biāo)簽,如果你確實(shí)需要,可以這么寫:goto case ("ry03");或goto default。

case ("ry03"):

Console.WriteLine("ry03");

break;

default:

Console.WriteLine("default");

break;

}

}

}

class RySwitchTestApp

{

public static void Main()

{

RySwitchTest rst = new RySwitchTest("ry02");

rst.SwitchStrProperty();

}

}



陷阱十.C#需要明確的賦值操作

C#要求必須明確地進(jìn)行賦值操作,這就意味所有變量在使用前必須被賦值。因此,盡管你可以聲明未初始化的變量,但在它擁有值之前是不可以被傳遞到方法的。

這就引出了一個(gè)問題—當(dāng)你僅僅是想將變量用作一個(gè)“出”參數(shù)按引用傳遞給方法時(shí)。例如,假定有個(gè)方法,返回當(dāng)前的小時(shí)、分鐘和秒。如果這么寫:

int theHour;

int theMinute;

int theSecond;

timeObject.GetTime( ref theHour, ref theMinute, ref theSecond)

編譯將出錯(cuò),因?yàn)樵谑褂胻heHour、theMinute和theSecond前,它們沒有被初始化:

Use of unassigned local variable 'theHour'

Use of unassigned local variable 'theMinute'

Use of unassigned local variable 'theSecond'

可以將它們初始化為0或者其它什么無(wú)傷大雅的值以讓討厭的編譯器安靜下來(lái):

int theHour = 0;

int theMinute = 0;

int theSecond = 0;

timeObject.GetTime( ref theHour, ref theMinute, ref theSecond)

但是這種寫法實(shí)在太愚蠢!我們的本意不過(guò)是想把這些變量按引用傳遞到GetTime,在其中改變它們的值。為了解決這個(gè)問題,C#提供了out參數(shù)修飾符。這個(gè)修飾符避免了對(duì)引用參數(shù)也要初始化的需求。例如,為GetTime提供的參數(shù)沒有提供給方法任何信息,它們僅僅是想從方法里取得信息。因此,把這三個(gè)參數(shù)都標(biāo)記為out型的,就避免了在方法外初始化它們的需要。但當(dāng)從被傳入的方法返回時(shí),out參數(shù)必須被賦值。下面是改變后的GetTime參數(shù)聲明:

public void GetTime(out int h, out int m, out int s)

{

h = Hour;

m = Minute;

s = Second;

}

下面則是對(duì)GetTime方法的新的調(diào)用方式:

timeObject.GetTime( out theHour, out theMinute, out theSecond);

【譯注:完整示例如下:

C#:[例1:使用ref修飾的方法參數(shù)]

using System;

class RyRefTest

{

public RyRefTest()

{

this.IntField = 1;

this.StrField = "StrField";

}

protected int IntField;

protected string StrField;

public void GetFields(ref int AInt, ref string AStr)

{

AInt = this.IntField;

AStr = this.StrField;

}

}

class RyRefTestApp

{

public static void Main()

{

RyRefTest rrt = new RyRefTest();

int IntVar = 0;//如果是int IntVar; 編譯器會(huì)報(bào)使用了未賦值的變量IntVar

string StrVar = "0";//如果是string StrVar; 編譯器會(huì)報(bào)使用了未賦值的變量StrVar

rrt.GetFields(ref IntVar, ref StrVar);

Console.WriteLine("IntVar = {0}, StrVar = {1}", IntVar, StrVar);

}

}



C#:[例2:使用out修飾的方法參數(shù)]

using System;

class RyRefTest

{

public RyRefTest()

{

this.IntField = 1;

this.StrField = "StrField";

}

protected int IntField;

protected string StrField;

public void GetFields(out int AInt, out string AStr)

{

AInt = this.IntField;

AStr = this.StrField;

}

}

class RyRefTestApp

{

public static void Main()

{

RyRefTest rrt = new RyRefTest();

int IntVar;//這樣就可以了,如果寫成int IntVar = 0;當(dāng)然也沒問題J

string StrVar; //這樣就可以了,如果寫成string StrVar = "0";當(dāng)然也沒問題J

rrt.GetFields(out IntVar, out StrVar);

Console.WriteLine("IntVar = {0}, StrVar = {1}", IntVar, StrVar);

}

}



主站蜘蛛池模板: 亚洲第一网站免费视频 | 日本三级视频在线播放 | 色噜噜影院 | 亚洲操片 | 日韩精品一区二区三区 在线观看 | 色网站在线观看 | 亚洲大香伊人蕉在人依线 | 午夜私人福利影院 | 亚洲94vvv男人的天堂五月 | 亚洲男人天堂视频 | 亚洲欧洲在线观看 | 日韩一级影院 | 夭天干天天做天天免费看 | 天天干天天爽天天射 | 午夜精 | 小明永久免费看aⅴ片 | 亚欧乱色束缚一区二区三区 | 青草国产在线视频 | 欧美怡红院免费的全部视频 | 色综合色综合色综合色综合 | 亚洲精品91| 天天草狠狠干 | 亚洲人成激情在线播放 | 青青草免费观看视频 | 午夜欧美视频 | 日韩久久综合 | 香蕉视频在线免费播放 | 在线观看视频污 | 香蕉漫画基地成人 | 亚洲欧美日韩精品久久久 | 性性欧美| 五月天婷婷激情网 | 亚洲国产精品久久精品成人 | 欧美一区二区免费 | 天天操天天干天天操 | 日本免费网站视频www区 | 天天色综合4 | 天堂资源在线 | 亚洲最新在线视频 | 一级做a爰片久久毛片美女图片 | 欧美视频第一页 |