国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開(kāi)發(fā) > 綜合 > 正文

C# 2.0對(duì)現(xiàn)有語(yǔ)法的改進(jìn)

2024-07-21 02:24:44
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

[自序]

盡管microsoft visual studio .net 2005(過(guò)去好像叫visual studio .net 2004)一再推遲其發(fā)布日期,但廣大開(kāi)發(fā)者對(duì)其的猜測(cè)以及各種媒體對(duì)其各方面的“曝光”也似乎已經(jīng)充斥了網(wǎng)絡(luò)。但與c#有關(guān)的文章似乎無(wú)外乎兩個(gè)方面:vs.net 2005 ide特性、介紹c# 2.0中引入的“四大特性(泛型、匿名方法、迭代器和不完整類型)”。對(duì)ide的研究我不想談了,微軟就是微軟,他的窗口應(yīng)用程序總是沒(méi)得說(shuō)的。而就語(yǔ)言本身的改進(jìn)來(lái)說(shuō),在我聽(tīng)完了anders hejlsberg在microsoft professional developers conference 2003(2003.10, los angeles, ca)上的演講后,發(fā)現(xiàn)除了這四大特性之外,還有一些鮮為人知的特性,甚至在微軟官方的文檔《c# language specification version 2.0》中都沒(méi)有提到。而這些特性卻更加提高了語(yǔ)言的邏輯性。于是我編寫(xiě)了大量實(shí)際程序研究了這些特性,終于著成本文。本打算發(fā)表在《csdn開(kāi)發(fā)高手》雜志上的,可無(wú)奈水平有限,只能留在這個(gè)角落里貽笑大方了。希望能夠?qū)δ切?duì)c#語(yǔ)言有著濃厚興趣的朋友有些幫助。

——lover_p 于北京工業(yè)大學(xué)1號(hào)樓221寢室

[修訂說(shuō)明]

2004-08-24
第一次修訂。修改了大量的錯(cuò)別字和文法錯(cuò)誤。添加了對(duì)global限定符的介紹。
[正文]

微軟在其即將推出的c#2.0(visual c# whidbey)中,添加了許多令程序員感到振奮的新特性。除了泛型(generic)、迭代器(iterator)、匿名方法(anonmynous)和不完整類型(partial type)等重大的改進(jìn),還對(duì)現(xiàn)有的語(yǔ)法細(xì)節(jié)進(jìn)行了很大的改進(jìn),極大地方便了.net框架程序設(shè)計(jì)的工作,并且進(jìn)一步加強(qiáng)了c#語(yǔ)言獨(dú)有的高邏輯性。在本文中,我將向大家介紹一下這些改進(jìn)。(文中c#指代的是c#1.2及以前的版本,而c#2.0指代的是微軟尚未正式推出的c# whidbey;文章中的所有代碼均在版本號(hào)為8.00.30703.4的c#編譯器下進(jìn)行了測(cè)試,標(biāo)有*的錯(cuò)誤消息得自版本號(hào)為7.10.3052.4的c#編譯器。)

[內(nèi)容]

靜態(tài)類
屬性的可訪問(wèn)性限定
命名空間別名
global限定符
編譯器指令
固定大小緩沖區(qū)
參考文獻(xiàn)
 

靜態(tài)類
使用c#進(jìn)行.net框架程序設(shè)計(jì)的人應(yīng)該都知道,無(wú)法將一個(gè)類聲明為靜態(tài)的。例如,下面的類聲明:

public static class a {
static int i;
}

在c#中是無(wú)效的,當(dāng)我們嘗試編譯這段代碼時(shí)會(huì)得到下面的編譯錯(cuò)誤*:

error cs0106: 修飾符“static”對(duì)該項(xiàng)無(wú)效

由于無(wú)法用static修飾符修飾一個(gè)類,我們?cè)陬愔锌偸悄軌蚣嚷暶黛o態(tài)成員又聲明實(shí)例成員。這無(wú)疑會(huì)帶來(lái)很大的靈活性。但是,如果我們希望一個(gè)類是靜態(tài)的,也就是希望強(qiáng)制要求這個(gè)類中的所有成員都應(yīng)該為靜態(tài)的,就無(wú)能為力了,唯一能做的就是自己注意將所有的成員聲明為static。當(dāng)我們忘記對(duì)一個(gè)本應(yīng)是靜態(tài)的成員使用static修飾符(盡管這是一個(gè)“低級(jí)錯(cuò)誤”,但仍有可能發(fā)生)時(shí),將會(huì)產(chǎn)生難以預(yù)料的錯(cuò)誤。最重要的是,對(duì)于一個(gè)邏輯上的靜態(tài)類(所有成員均使用static修飾符進(jìn)行聲明的類),我們甚至可以聲明該類的一個(gè)變量并使用new操作符產(chǎn)生該類的實(shí)例!這顯然不是我們所期望的。

而在c#2.0中,則提供了靜態(tài)類這一概念,允許static修飾符對(duì)類進(jìn)行修飾,上面的代碼得以通過(guò)編譯。如果一個(gè)類聲明中包含了static修飾符,那么這個(gè)類中的所有成員將被強(qiáng)制要求聲明為靜態(tài)的。這時(shí),如果我們故意在類中聲明實(shí)例成員或是不小心忘記了成員聲明中的static修飾符,如下面代碼所示:

public static class a {
int i;
}

則編譯器會(huì)報(bào)告錯(cuò)誤:

error cs0708: 'a.i': cannot declare instance members in a static class

同時(shí),如果我們聲明該類的變量或是試圖建立該類的一個(gè)實(shí)例時(shí),如下面的代碼:

public class test {
a a; // error cs0723
void foo() {
a = new a(); // error cs0712
}
}

則會(huì)得到下面的兩個(gè)編譯錯(cuò)誤:

error cs0723: cannot declare variable of static type 'a'
error cs0712: cannot create an instance of the static class 'a'

很顯然,c#2.0中對(duì)靜態(tài)類的支持極大程度地避免了我們?cè)跁?shū)寫(xiě)程序中的意外失誤,尤其是加強(qiáng)了靜態(tài)類的邏輯性,提高了代碼的可讀性。

屬性的可訪問(wèn)性限定
c#為我們提供了相當(dāng)方便的屬性定義,使得我們可以像訪問(wèn)類的公有變量成員那樣訪問(wèn)類的屬性,但還可以同時(shí)得到像訪問(wèn)函數(shù)那樣的安全性。然而,c#只允許屬性的設(shè)置動(dòng)作(set{...})和獲取動(dòng)作(get{...})具有相同的可訪問(wèn)性(由屬性聲明中的public、internal和private等修飾符指定)。那么,當(dāng)我們希望允許從任何程序集中的類獲取一個(gè)特定類的屬性,但只允許該類所在的程序集或該類的私有成員才能設(shè)置該屬性時(shí),我們只能將這個(gè)屬性聲明為公有且只讀(即使用public修飾符聲明但只有g(shù)et{}域),而內(nèi)部的或私有的成員只能通過(guò)設(shè)置與該屬性相關(guān)的內(nèi)部或私有的變量成員的值來(lái)完成屬性的設(shè)置工作:

public class a {
int _intvalue; // 與屬性相關(guān)的一個(gè)int類型的成員變量

// 公有且只讀的屬性,允許任何類獲取該屬性的值:
public int value {
get { return _intvalue; }
}

// 下面的方法需要設(shè)置上面的屬性,
// 但只能通過(guò)訪問(wèn)私有成員變量來(lái)完成,
// 并且要另外進(jìn)行錯(cuò)誤處理
private void somemethod() {
int i;
// ......
// 下面的if-else語(yǔ)句僅用來(lái)設(shè)置屬性值:
if(0 < i && i < 10) {
_intvalue = i;
}
else {
// 錯(cuò)誤處理
}
}
}

很明顯,這種做法是非常麻煩的。如果在多個(gè)地方改變了成員變量的值會(huì)使代碼變得冗長(zhǎng)不可讀,還很有可能會(huì)產(chǎn)生錯(cuò)誤,譬如該類有另外一個(gè)方法:

private void anothermethod() {
int i;
// ......
// 下面的if-else語(yǔ)句僅用于設(shè)置屬性值,
// 但其對(duì)i的區(qū)間檢測(cè)發(fā)生了錯(cuò)誤
if(0 < i && i <= 10) { // 注意這里的 <= 運(yùn)算符
_intvalue = i;
}
// 并且沒(méi)有進(jìn)行錯(cuò)誤處理
// ......
}

上面的方法對(duì)將要賦給私有變量成員的值的檢查區(qū)間是錯(cuò)誤的,這種錯(cuò)誤是很有可能發(fā)生的。一旦調(diào)用了這個(gè)方法,_intvalue很有可能具有錯(cuò)誤的值,而訪問(wèn)了value屬性的外部程序集將會(huì)出現(xiàn)邏輯錯(cuò)誤。這種錯(cuò)誤的解決是相當(dāng)困難的。并且,如果一個(gè)小組中的其他成員負(fù)責(zé)設(shè)計(jì)同一程序集中其他的類,要求他們?cè)诜椒ㄖ袝?shū)寫(xiě)如此大量的代碼并要進(jìn)行錯(cuò)誤檢查是不人道的。

當(dāng)然,我們可能會(huì)想到將這種設(shè)置屬性值的工作放到一個(gè)內(nèi)部方法中集中進(jìn)行:

// 程序集內(nèi)部的類或該類的私有成員通過(guò)
// 下面的內(nèi)部方法對(duì)上面的屬性進(jìn)行設(shè)置工作
internal void _setintvalue(int newvalue) {
if(0 < newvalue && newvalue < 10) {
_intvalue = newvalue;
}
else {
throw new system.invalidargumentexception (
“the new value must greater than 0 and less than 10”
);
}
}

// 下面的方法需要對(duì)上述屬性進(jìn)行設(shè)置
private void somemethod() {
int i;
// ......
_setintvalue(i); // 通過(guò)調(diào)用內(nèi)部方法進(jìn)行
}

這樣做雖然避免了邏輯錯(cuò)誤的出現(xiàn)(至少使出現(xiàn)了錯(cuò)誤時(shí)的解決工作變得容易),但其可讀性仍然不理想,尤其是邏輯性很差,與“屬性”本身的意義相去甚遠(yuǎn)。

然而c#2.0允許我們對(duì)屬性的get{}和set{}域分別設(shè)置可訪問(wèn)性,我們能夠?qū)⑸厦娴拇a簡(jiǎn)單地寫(xiě)作:

public class a {
int _intvalue; // 與屬性相關(guān)的一個(gè)int類型的成員變量

// 公有的屬性,
// 允許任何類獲取該屬性的值,
// 但只有程序集內(nèi)部的類和該類中的私有成員
// 能夠設(shè)置屬性的值
public int value {
get {
return _intvalue;
}
internal set {
if(0 < value && value < 10) {
_intvalue = value;
}
else {
throw new system.invalidargumentexception (
“the new value must greater than 0 and less than 10”
);
}
}
} // property

// 下面的方法需要對(duì)上述屬性進(jìn)行設(shè)置
private void somemethod() {
int i;
// ......
value = i;
}
}

尤其在程序集中的其他類的成員中訪問(wèn)該屬性時(shí)相當(dāng)方便:

// 這是同一個(gè)程序集中另外的一個(gè)類:
public class b {
public a somemethod() {
a a = new a();
a.value = 8; // 這里對(duì)屬性進(jìn)行設(shè)置,方便!
return a;
}
}

可以看出,能夠?qū)傩缘墨@取和設(shè)置操作分別設(shè)置可訪問(wèn)性限定極大地增強(qiáng)了c#程序的可讀性和語(yǔ)言邏輯性,寫(xiě)出的程序也具有更強(qiáng)的可維護(hù)性。

命名空間別名
在c#中,使用類(如聲明成員變量或調(diào)用靜態(tài)方法等)的時(shí)候需要指定類的完全名稱,即命名空間前綴加類的名字。如果我們要在控制臺(tái)上打印“hello, world!”,則需要寫(xiě):

system.console.writeline(“hello, world!”);

其中,system是命名空間,console是類的名字,writeline()是我們要調(diào)用的方法。

這樣的要求顯然會(huì)使代碼變得異常冗余。因此,c#為我們提供了using關(guān)鍵字(指令)。通過(guò)使用using指令,我們可以向編譯器指定一系列命名空間,當(dāng)程序中出現(xiàn)了類名字時(shí),編譯器會(huì)自動(dòng)到這些命名空間中查找這個(gè)類。因此,上面的代碼可以寫(xiě)作:

using system;
// ......
public class test {
public static void main() {
console.writeline(“hello, world!”);
}
}

呵呵,這不就是經(jīng)典的“hello world”范例么?很顯然,這種寫(xiě)法方便得多,可以極大地提高開(kāi)發(fā)效率。

然而,兩個(gè)命名空間中很可能具有同名的類,而我們恰好需要用到這些同名的類。這種情況會(huì)經(jīng)常發(fā)生。譬如在.net框架類庫(kù)中就存在有三個(gè)timer類:system.timer.timer、system.threading.timer和system.windows.forms.timer。我們很可能需要兩個(gè)timer類:一個(gè)system.timer.timer用于在后臺(tái)以固定的時(shí)間間隔檢查應(yīng)用程序或系統(tǒng)狀態(tài),一個(gè)system.windows.forms.timer用于在用戶界面中顯示簡(jiǎn)單動(dòng)畫(huà)。這時(shí),盡管我們使用了using指令,我們?nèi)匀恍枰谶@些類出現(xiàn)時(shí)加上命名空間:

using system.timer;
using system.windows.forms;
// ......
public class mainform : form {
system.timer.timer checktimer;
system.windows.forms.timer animatetimer;
// ......
}

這樣的程序仍然顯得冗長(zhǎng)。

在c#2.0中,using指令的使用得到了擴(kuò)展,我們可以使用using指令來(lái)為命名空間指定一個(gè)別名。當(dāng)我們需要引用這個(gè)命名空間時(shí),可以簡(jiǎn)單地使用它的別名。為命名空間創(chuàng)建一個(gè)別名時(shí),我們使用using指令的擴(kuò)展用法:using alias = namespace,即可為命名空間namespace指定一個(gè)別名alias。而別名和命名空間的使用方法完全相同。當(dāng)我們引用一個(gè)命名空間中的類型的時(shí)候,只需要在命名空間后面加一個(gè)圓點(diǎn)“.”再跟上類型名稱即可;而引用一個(gè)別名所代表的命名空間中的類型時(shí),寫(xiě)法是一樣的。那么,上面的例子可以寫(xiě)作:

using systimer = system.timer;
using winform = system.windows.forms;
// ......
public class mainform : winform.form {
systimer.timer checktimer; // 與命名空間的使用完全相同
winform.timer animatetimer;
// ......
}

我們可以看到,這樣的代碼要簡(jiǎn)潔得多。

global限定符
在c#2.0以前,在使用命名空間時(shí)還有一個(gè)非常細(xì)微的問(wèn)題。這就是c#命名空間的查找方式。考慮下面這個(gè)例子:

using system;

namespace mynamespace {
namespace system {
public class myconsole {
public void writeline(string str) {
system.console.writeline(str); // 注意這一行!
}
}
}
}

這里我在自己的命名空間內(nèi)聲明了一個(gè)system命名空間,并在其中模擬了控制臺(tái)類。我希望它通過(guò)調(diào)用system.console類的方法來(lái)模擬控制臺(tái)的行為。這個(gè)程序片斷是沒(méi)有語(yǔ)法問(wèn)題的,當(dāng)仍然不能通過(guò)編譯。其主要原因是c#的命名空間作用域和普通變量的作用域規(guī)則類似,總是查找最近的聲明,并且內(nèi)部聲明可以覆蓋外部聲明。因此,這段代碼中標(biāo)有注釋的一行在編譯的時(shí)候編譯器會(huì)提示找不到類mynamespace.system.console——它試圖在我自己的命名空間里找system.console類!

在c#2.0以前,這個(gè)問(wèn)題對(duì)于類庫(kù)的設(shè)計(jì)者來(lái)說(shuō)是非常頭疼的。唯一的解決方法就是盡量在自己的命名空間內(nèi)不使用全局命名空間中的名字。但是,由于類庫(kù)開(kāi)發(fā)者眾多,難免會(huì)出現(xiàn)類似的情況;而且,這樣做還會(huì)導(dǎo)致既是在自己的命名空間中也不能使用可讀性高而又簡(jiǎn)潔的名字,這無(wú)疑傷害了語(yǔ)言的邏輯性和簡(jiǎn)潔性。

然而,c#2.0引入了global關(guān)鍵字,允許我們從全局選取命名空間。下面這個(gè)圖示從.net命名空間的布局說(shuō)明了global關(guān)鍵字的地位:


--------------------------------------------------------------------------------

圖示1:global關(guān)鍵字的地位
在c#1.x中:

+++ who's the root? +++
|
+- system (namespace)
| |
| +- console (class)
| +writeline (method)
| +- int32 (struct)
| +- ...
|
+- mynamespace (namespace)
|
+- system ([sub]namespace)
+ myconsole (class)

在c#2.0中

global (!!!root!!!)
|
+- system (namespace)
| |
| +- console (class)
| +writeline (method)
| +- int32 (struct)
| +- ...
|
+- mynamespace (namespace)
|
+- system ([sub]namespace)
+ myconsole (class)


--------------------------------------------------------------------------------

這樣一來(lái),我們就能通過(guò)使用global關(guān)鍵字輕易地解決命名空間的沖突問(wèn)題。上面的例子也就能夠重寫(xiě)為:

using system;

namespace mynamespace {
namespace system {
public class myconsole {
public void writeline(string str) {
global.system.console.writeline(str); // 注意這一行!
}
}
}
}

編譯器指令
在我們調(diào)試c#程序時(shí),經(jīng)常會(huì)聲明一些臨時(shí)變量用來(lái)監(jiān)測(cè)程序狀態(tài),并在調(diào)試完成后將這些聲明刪除。而當(dāng)我們聲明了這樣的臨時(shí)變量,在調(diào)試過(guò)程中卻沒(méi)有用到的時(shí)候,我們通常會(huì)得到大量的如:

warning cs0168: the variable 'exp' is declared but never used

的警告。然而,我們很清楚這樣的警告是無(wú)害的。同樣,很多其他時(shí)候我們也會(huì)得到一些警告,但我們不得不從大量的無(wú)害的警告中尋找我們需要的錯(cuò)誤消息。

然而,c#2.0為我們提供了一條新的編譯器指令:pragma warning,使得我們能夠在一段代碼中禁止一些我們確認(rèn)無(wú)害的警告(通過(guò)指定警告的編號(hào))。以前,這種工作只能由特定的編譯器選項(xiàng)(譬如microsoft visual c#編譯器的/nowarn)或相應(yīng)的ide選項(xiàng)(如microsoft visual studio .net 2003中的項(xiàng)目屬性頁(yè)中的相應(yīng)選項(xiàng))來(lái)完成。而且,通過(guò)編譯環(huán)境來(lái)隱藏警告將導(dǎo)致在編譯整個(gè)項(xiàng)目或整個(gè)源文件的過(guò)程中所有相應(yīng)的警告都會(huì)被隱藏。如果我們僅僅知道在某一個(gè)代碼塊中一個(gè)警告是無(wú)害的,但對(duì)于代碼的其它部分,我們還是希望看到這個(gè)警告消息時(shí),這種做法就無(wú)能為力了。這個(gè)時(shí)候,我們只有通過(guò)pragma warning指令來(lái)命令編譯器僅僅隱藏某一個(gè)代碼塊中相應(yīng)的警告。我們可以用下列代碼來(lái)禁止產(chǎn)生上面的例子中所述的“未使用參數(shù)”的警告:

public class test {
public void somemethod() {
// 下面的編譯器指令禁止了“未使用參數(shù)”的警告:
#pragma warning disable 0168
int tempstatus;
// ......
// 下面的編譯器指令重新允許產(chǎn)生“未使用參數(shù)”的警告:
#pragma warning restore 0168
}
}

這樣,當(dāng)編譯器編譯somemethod()方法時(shí),將不會(huì)產(chǎn)生上述的“未使用參數(shù)”的警告,但在編譯其它代碼段時(shí),仍然會(huì)產(chǎn)生該警告,因?yàn)槲覀冇?pragma warning restore指令重新打開(kāi)了該警告。

固定大小緩沖區(qū)
最后,除了上述的一些特性外,c#2.0還提供了“固定大小緩沖區(qū)(fixed size buffers)”的新特性。即像c語(yǔ)言那樣可以在結(jié)構(gòu)中聲明一個(gè)固定大小的數(shù)組,這通過(guò)system.runtime.compilerservices.fixedbufferattribute屬性和fixed關(guān)鍵字實(shí)現(xiàn)(參見(jiàn)參考文獻(xiàn)第26頁(yè)):

[system.runtime.compilerservices.fexedbuffer]
public struct buffer {
public fixed char buffer[128];
}

但由于我所使用的編譯器尚未支持這一特性,手頭又沒(méi)有相應(yīng)的資料,在此就不做介紹了。

 

以上是我對(duì)c#2.0中除了泛型、迭代器、匿名方法和分部類型等重大改進(jìn)之外的一些對(duì)現(xiàn)有特性進(jìn)行的改進(jìn)的簡(jiǎn)要介紹。這些改進(jìn)看起來(lái)很細(xì)微,卻極大程度地增強(qiáng)了c#語(yǔ)言的邏輯性,使得我們能夠?qū)懗龈悠燎铱删S護(hù)性更強(qiáng)的代碼。我的介紹是非常簡(jiǎn)略的,甚至可能有錯(cuò)誤,希望大家指教。(聯(lián)系方式:[email protected])

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 体育| 河北区| 惠州市| 依兰县| 张家界市| 木里| 营口市| 察雅县| 高安市| 西城区| 望谟县| 社会| 高青县| 莎车县| 长岭县| 汝南县| 武隆县| 宁南县| 杂多县| 海城市| 庆安县| 长汀县| 商都县| 屏边| 云南省| 铅山县| 苏尼特左旗| 黑龙江省| 家居| 二连浩特市| 旬阳县| 大洼县| 瑞昌市| 即墨市| 丰顺县| 仙居县| 鹤山市| 黎城县| 尉犁县| 福安市| 申扎县|