C# 認識物件 - HackMD

文章推薦指數: 80 %
投票人數:10人

this 最經典的用法便是用在建構式,this 關鍵字用來強調當前執行的主角,在建構式中以區分跟主角相同名稱的變數傳遞值。

public class Employee { private string alias; ...       Published LinkedwithGitHub Like Bookmark Subscribe ######tags:`自主學習` #C#認識物件   ##♟屬性Properties **屬性**是提供彈性機制以讀取、寫入或計算私用欄位值的成員。

使用屬性時可將其視為公用資料成員,但實際上屬性是名為「存取子」的特殊方法。

如此可讓資料更容易存取,同時有助於提升方法的安全性和彈性。

###set、get **set**搭配**value**(存取讀取值)用來指派新值、**get**用來傳回屬性值。

```csharp publicclassTimePeriod{ privateintsecond; publicdoubleGetMinute{ get{returnsecond/60;} set{second=value;} } } Minutet=newMinute(); t.GetMinute=600; Console.WriteLine($"Timeinhours:{t.GetMinute}"); //Timeinhours:10 ``` 以上的範例就是屬性的實作,可以發現屬性相對於一般方法更加安全,因為屬性成功做到**封箱**的功能。

程式中接觸到屬性的方法只有運用set的管道,而輸出也被管控限制於get出口。

**屬性**在程式功能的維護方面相當出色,因為本身與外界程式並沒有直接性的接觸,因此Debug、加入新功能(在屬性區塊中加入即可)較為容易 get與set可以單獨存在,一般單獨存在set的類別可以將其加上**readonly**的修飾詞。

###建構式呼叫黑盒 **建構式呼叫黑盒**是當我們建造物件時,直接於建構式中傳遞參數,以此簡化程式碼,也將物件本身與參數的連結更加強調。

```csharp usingSystem; publicclassPerson { privatestring_firstName; privatestring_lastName; publicPerson(stringfirst,stringlast) { _firstName=first; _lastName=last; } publicstringName=>$"{_firstName}{_lastName}"; } publicclassExample { publicstaticvoidMain() { varperson=newPerson("Magnus","Hedlund"); Console.WriteLine(person.Name); } } //Theexampledisplaysthefollowingoutput: //MagnusHedlund ``` 以上的範例呈現了建造物件時,同時間設置好參數,一兼兩顧。

但我相信大家都注意到了,```=>```這是三毀。

####Lambda運算子 ```=>```名稱就是Lambda運算子喔,有```=>```在的式子就是Lambda運算式(Lambdaexpression)。

```=>```的功能可以理解為:```=>```,也類似於一個精簡函式的寫法。

```csharp //無Lambdaexpression publicsquare(intx) { returnx*x; } Console.WriteLine(square(5)); //有Lambdaexpression Funcsquare=x=>x*x; //FuncT是泛型喔 //Func Console.WriteLine(square(5)); ``` 當然了,這只是最簡單的Lambda參數式,在更上面的範例其實用到了較為進階的手法。

```csharp publicstringName=>$"{_firstName}{_lastName}"; ``` 這行程式碼可以理解為,當我呼叫Name他會直接回傳```=>```右方的值 更多關於[**Lambda運算子**](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#code-try-4)的資訊可以點連結進入參考喔。

###自動實作屬性 自動實作屬性也就是將get與set部分程式碼省略,直接交由編譯器判斷,並將原先需要做的設定,寫在外部的程式碼中傳遞。

如此一來,相對於```=>```運算子,可以在黑盒內有明確的變數或參數名稱,但也同時將黑箱打開,將其需傳遞的參數變為public型別了。

```csharp publicclassSaleItem { publicstringName {get;set;} publicdecimalPrice {get;set;} } classProgram { staticvoidMain(string[]args) { varitem=newSaleItem{Name="Shoes",Price=19.95m}; Console.WriteLine($"{item.Name}:sellsfor{item.Price:C2}"); } } //Theexampledisplaysoutputlikethefollowing: //Shoes:sellsfor$19.95 ``` 如果同時擁有get、set,就必須都使用自動實作屬性。

##🔗函式多載MethodOverloading 其實函式多載的概念非常簡單,也就是程式能夠分辨相同名稱但是不同參數型別傳遞的函式。

```csharp publicclassExample { publicintAdd(inta,intb) { returna+b; } publicstringAdd(stringa,stringb) { returna+b; } } Example.Add(1,2); Example.Add("hello",",world!"); ``` 雖然名稱一樣,但是因為傳遞參數的不同,因此程式能夠判斷你呼叫的是哪個函式。

但是,假如我呼叫的函式為:```Example.Add(1,2,3);``` 此時編譯器便會開始依照下列順序嘗試呼叫。

1.嘗試符合參數型態但不符合參數個數的方法 2.編譯錯誤 需要注意的一點是,編譯器在方法多載時只看參數型別選擇函式而非回傳值。

```csharp publicclassExample { publicintAdd(inta,intb) { returna+b; } publicdoubleAdd(inta,intb) { returna+b; } } ``` 以上的例子中,編譯器會視2種方法為同一種,因此造成編譯錯誤。

##🎗泛型Generics **泛型**?聽都沒聽過。

但是假如你用過List的宣告其實已經使用到泛型的概念,只是C#將宣告的部分包裝起來,直接將List丟給我們學習。

現在我們來一虧泛型的全貌吧! ###時機 泛型的功效使我們只需宣告一種方法,而泛型會幫我們處理變數傳遞的宣告問題。

那有什麼用呢?泛型減少了程式重複宣告方法或類別只為了配合不同傳進來的參數型別而造成的累贅,也方便了程式的閱讀性更避免了造成多載的問題。

因此,當我們需要**一個會有不同參數型別傳入的方法或類型,但其功能完全相同**,這時,就是我們使用泛型的最佳時機。

###宣告 ####泛型方法GenericMethod ```csharp publicintGenericMethod(intparam) { returnparam; } GenericMethod(1)//呼叫 ``` ```csharp publicTGenericMethod(Tparam) { returnparam; } GenericMethod(1) ``` 觀察過後,會發現泛型與一般宣告並無太大歧異,將泛型區塊中所有與傳入參數型別相關之關鍵字替代為``````中的T(Template)。

呼叫的時候於。

####泛型類別GenericClass ```csharp publicclassGenericClass { Titem; publicvoidUpdateItem(TnewItem) { item=newItem; } } GenericClassmyClass=newGenericClass(); myClass.UpdateItem(5); ``` 運用上大同小異,呼叫時於建立時便先傳遞變數型別,之後使用其方法的時候再傳遞參數。

##👨‍👦繼承Inheritance **繼承**即**子類別**有**父類別**部分程式效能。

程式中,我們可以在子類別中不需要宣告特定變數或方法,就可以使用在父類別中已經宣告為public與protected的變數或方法。

在最初步的理解,我們可以想成子類別的程式上面,就是父類別的程式,然後我們將類別拔掉,就變成是一般我們最熟悉的簡單程式。

觀念上,**繼承**相當強調**子類別isa父類別**的關係,例如:**黑面琵鷺isa候鳥**,**候鳥isa鳥**。

這觀念與將來介紹的介面Interface不同,需要多多注意。

###類別class ####方法宣告 +**Public** 在其衍生類別中與外部程式中也可以使用,沒有任何限制。

+**Private** 僅限於父類別中的程式使用,一般用於宣告於父類別有但子類別沒有的專有行為。

其中,**建構式**不需要另外作Private的宣告,因為建構式為建構此類別的依據,且子類別會有自己的建構式,建構式建構出複數個物件於一個物件上,在邏輯上是行不通的。

+**Protected** 介於**Public**與**Private**之間,子類別可以使用父類別中的函式,但外部不能使用。

####父類別Parent/Baseclass ```csharp publicclassParent { publicintspeed; publicParent { //Constructorwillnotinheritedbyanyderivedclasses. } publicvoidWalk() { } //dosomething } ``` ####子類別Child/Derivedclass ```csharp publicclassChild:Parent { speed++;//不須宣告即可使用父類別的變數 Walk()//不須宣告即可使用父類別的方法 //dootherthings } ``` ###base關鍵字 認識basa關鍵字前,我們必須重新理解繼承的相互關係。

總歸一句話,**thebaseclassof```Derivrdclass```is```Baseclass```.** 下面的例子中,thebaseclassof```Point3D```is```Point```,andthebaseclassof```Point```is```object```. ####OverridingConstructor ```csharp publicclassPoint { publicintx,y; publicPoint(intx,inty){ this.x=x; this.y=y; } } ``` ```csharp publicclassPoint3D:Point { publicintz; publicPoint3D(intx,inty,intz):base(x,y){ this.z=z; } } ``` 因此我們在這邊可以將存在於Derivedclass中的所有base關鍵字視為其Baseclass之**名字**。

換句話說,這邊的```Point3D```中的```base```就形同於```Point```。

所以這段程式怎麼運行的呢?運行至base關鍵字後,程式將會呼叫Bassclass中的Constructor。

執行完再回至Derivedclass中的Constructor中。

####OverridingMethod ```csharp publicclassPerson { protectedstringssn="444-55-6666"; protectedstringname="JohnL.Malgraine"; publicvirtualvoidGetInfo() { Console.WriteLine("Name:{0}",name); Console.WriteLine("SSN:{0}",ssn); } } classEmployee:Person { publicstringid="ABC567EFG"; publicoverridevoidGetInfo() { //CallingthebaseclassGetInfomethod: base.GetInfo(); Console.WriteLine("EmployeeID:{0}",id); } } classTestClass { staticvoidMain() { EmployeeE=newEmployee(); E.GetInfo(); } } /* Output Name:JohnL.Malgraine SSN:444-55-6666 EmployeeID:ABC567EFG */ ``` 以上的範例中,Employeeclass中的```base.GetInfo()```相當於```Person.GetInfo()```,也就是呼叫在Personclass中相同名字(overriding)的方法。

##🎭多形Polymophism **多形**是一種較為特別的繼承關係。

由於一個BassClass可以擁有多個DerivedClass,在某些程式中,我們很常會需要在DerivedClass重複執行某一特定方法或函式,這時我們就可以用多形的概念。

也就是在BassClass中寫下該方法,再到DerivedClass中呼叫BassClass的方法。

這樣一來我們就能不用每個方法重覆寫於每個DerivedClass。

```csharp publicclassShape { //Afewexamplemembers publicintX{get;privateset;} publicintY{get;privateset;} publicintHeight{get;set;} publicintWidth{get;set;} //Virtualmethod publicvirtualvoidDraw() { Console.WriteLine("Performingbaseclassdrawingtasks"); } } publicclassCircle:Shape { publicoverridevoidDraw() { //Codetodrawacircle... Console.WriteLine("Drawingacircle"); base.Draw(); } } publicclassRectangle:Shape { publicoverridevoidDraw() { //Codetodrawarectangle... Console.WriteLine("Drawingarectangle"); base.Draw(); } } publicclassTriangle:Shape { publicoverridevoidDraw() { //Codetodrawatriangle... Console.WriteLine("Drawingatriangle"); base.Draw(); } } //Polymorphismatwork#1:aRectangle,TriangleandCircle //canallbeusedwhereeveraShapeisexpected.Nocastis //requiredbecauseanimplicitconversionexistsfromaderived //classtoitsbaseclass. varshapes=newList { newRectangle(), newTriangle(), newCircle() }; //Polymorphismatwork#2:thevirtualmethodDrawis //invokedoneachofthederivedclasses,notthebaseclass. foreach(varshapeinshapes) { shape.Draw(); } /*Output: Drawingarectangle Performingbaseclassdrawingtasks Drawingatriangle Performingbaseclassdrawingtasks Drawingacircle Performingbaseclassdrawingtasks */ ``` 以上的例子便是多形的實作,我們重複呼叫了BaseClass的Shape方法,如此避免覆寫所造成的空間的累贅。

###📨Cast 當程式在編譯繼承時,會先創造出一個物件,再將他的型別轉由``````作參考。

例如:```Someclassclassname=newSomeclass()```,程式先是建出了Someclass物件再將物件轉由指派給最左邊的型別參考。

那,我們可不可以建造出一個物件再將他轉給他的Baseclass、Derivesclass參考呢? ![](https://i.imgur.com/bmUEtFW.png) ####📤Upcasting ```BaseClassclassname=newDerivedClass();``` 我們用白話一點的方式解釋,**我的本質是子類別,但把我當成父類別看待**。

一般來說,Upcasting不會造成編譯上的錯誤。

因為**繼承**本身有著方法繼承的特性,父類別一定有子類別的函式;換句話說,繼承強調的**isa**關係中,**子類別isa父類別**本來就是正確的。

所以當我們將子類別物件參考轉向父類別時(強制或非強制),並不會造成編譯錯誤。

```csharp publicclassBaseClass { publicvoidDoWork(){ Console.WriteLine("Upcasting"); } publicvoidSleep(){ Console.WriteLine("Sleeping"); } } publicclassDerivedClass:BaseClass { publicnewvoidDoWork(){ Console.WriteLine("Normal"); } } BaseClassExample=newDerivedClass(); Example.DoWork(); //Output:Upcasting Example.Sleep(); //Output:Sleeping ``` ####📥Downcasting ```DerivedClassclassname=newBaseClass();``` 我們用白話一點的方式解釋,**我的本質是父類別,但把我當成子類別看待**。

相對於Upacating,**Downcasting**容易發生錯誤,因為繼承強調的是**isa**關係而非**is**的指派關係,例如:人類isa哺乳類⭕,但哺乳類isa人類❌。

用最粗淺的想法,子類別比父類別多一些函式,所以比父類別強,因此有時就會發生父類別能力不足的錯誤。

```csharp publicclassBaseClass { publicvoidDoWork(){ Console.WriteLine("Normal"); } } publicclassDerivedClass:BaseClass { publicnewvoidDoWork(){ Console.WriteLine("Downcasting"); } publicnewvoidSleep(){ Console.WriteLine("Sleeping"); } } DerivedClassExample=(DerivedClass)newBaseClass(); Example.DoWork(); //Output:Downcasting Example.Sleep(); //Compileerror ``` ###🗳方法隱蓋MemberHiding 若是在DerivedClass中宣告與BaseClass具有相同格式的方法,就必須在DerivedClass的宣告前加上**new**修飾詞。

new與overriding是完全相反的概念,使用new會造成MemberHiding,也就是目前我在哪個Class我就優先使用的該Class的變數或是方法(Hideothermethods)。

```csharp publicclassHumanoid { //BaseversionoftheYellmethod publicvoidYell() { Debug.Log("HumanoidversionoftheYell()method"); } } publicclassEnemy:Humanoid { //ThishidestheHumanoidversion. newpublicvoidYell() { Debug.Log("EnemyversionoftheYell()method"); } } EnemyExample=newHumanoid(); Example.Yell(); (Humanoid)Example.Yell();//Upcasting //Output:EnemyversionoftheYell()method //Output:HumanoidversionoftheYell()method ``` :::info 所以這衍生了一個問題,**new**修飾詞到底甚麼時候使用? 在物件導向的程式中,只要是帶有**建立新東西**(**無論是變數或方法或物件**)的意思,就可以在前面加上new。

(雖然new真的超少用) 其實在我們可以這樣理解平常所做的宣告: ```csharp inta=10; newinta=10; ``` 這樣一來就了解了吧! ::: ###✒覆寫Overriding 事實上,在大多數情況,即使處於Upcasting的狀態,我們仍然希望能夠使用DerivedClass的方法,這時我們就可以使用**override**修飾詞。

override修飾詞會「延伸」基底類別的virtual方法,因此會優先參考override過後的方法。

```csharp publicclassHumanoid { //BaseversionoftheYellmethod publicvirtualvoidYell() { Debug.Log("HumanoidversionoftheYell()method"); } } publicclassEnemy:Humanoid { //ThishidestheHumanoidversion. publicoverridevoidYell() { Debug.Log("EnemyversionoftheYell()method"); } } EnemyExample=newHumanoid(); Example.Yell(); (Humanoid)Example.Yell();//Upcasting //Output:EnemyversionoftheYell()method //Output:EnemyversionoftheYell()method ``` 如此一來我們就可以避免Upcasting時呼叫到BaseClass的方法了。

但是假如我們要使用BaseClass呢?這時候就可以使用**base**關鍵字隨時呼叫,也因此override一般使用上比new還要更彈性。

:::info 在相同的成員上同時使用**new**和**override**是不正確的,因為這兩個修飾詞在意義上互斥。

new修飾詞會以相同名稱建立新成員,並使原始成員隱藏。

override修飾詞會擴充繼承成員的實作。

[**new詳細資訊**](https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/keywords/new-modifier) [**override詳細資訊**](https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/keywords/override) ::: ##👥介面Interfaces 說到這邊,大家都認為繼承無懈可擊了?對吧! 即使繼承相當方便,仍然是潘朵拉的盒子。

繼承過於直白,直白的可怕。

舉個例子:今天你已經實作了Fish的BassClass(有Swim()方法)及其DerivedClass們。

現在突然要加入**美人魚**這個物件,他可以繼承Fish嗎?呃。





應該算還可以吧?於是你加入了美人魚DerivedClass。

那如果是**潛艇**?他可以繼承Fish嗎?這未免太牽強了吧? 因此,大多數物件導向的程式語言有著**介面****Interface**這樣的功能。

如果說繼承是**BClassisaAClass**的關係,介面就是**BClassimplementAInterface**的關係。

以上的例子中,我們將Swim()定義為一種介面,FishClass、MermaidClass及Submarine一齊實作(**implement**)Swim()這個介面。

```csharp //Thisisabasicinterfacewithasinglerequired //method. publicinterfaceIKillable { voidKill(); } //ThisisagenericinterfacewhereTisaplaceholder //foradatatypethatwillbeprovidedbythe //implementingclass. publicinterfaceIDamageable { voidDamage(TdamageTaken); } publicclassAvatar:MonoBehaviour,IKillable,IDamageable { //TherequiredmethodoftheIKillableinterface publicvoidKill() { //Dosomethingfun } //TherequiredmethodoftheIDamageableinterface publicvoidDamage(floatdamageTaken) { //Dosomethingfun } } ``` 注意到了嗎?一般對於繼承,我們嚴格要求物件只能有一個父類別,但介面卻不受此限,因此一個物件可以實作多種介面的行為,更加彈性,也更方便加入新功能。

##📼擴充方法ExtensionMethod **擴充方法**是一種不必建造子類別及修改到原本類別的特殊作法,一般適用在你無法直接接觸到某類別的Sourcecode時,我們可以在外部**擴充**該類別的方法,再於其他地方以一般呼叫該類別其他方法使用此擴充方法。

```csharp publicstaticclassMyExtensions { publicstaticintWordCount(thisStringstr) //(this隨便一個參數名字) { returnstr.Split(newchar[]{'','.','?'}, StringSplitOptions.RemoveEmptyEntries).Length; } } ``` 外部呼叫 ```csharp usingMyExtensions//加上擴充方法宣告之該類別名稱 strings="HelloExtensionMethods"; inti=s.WordCount();//以String類別的方法使用 ``` ###static靜態類別 static是一個修飾詞,用來宣告靜態成員,可以與類別、欄位、方法、屬性、運算子、事件和建構函式搭配使用。

1.一開始載入時就存在,就佔據記憶體 2.不能也不用new就可以使用(因為已經占據記憶體了) 3.static的成員是大家共享的(使用同一區記憶體) 當然了,static非常一體兩面 +優點: 若使用在公用變數,可以共享記憶體 若使用在公用方法,大家都可以叫用 -缺點: 無論有沒有使用,它一開始就佔據記憶體空間。

因為共享很難控制存取權限 +特性 -靜態類別僅包含靜態成員 -不能使用new實體化 -屬密封類別,無法被繼承 -沒有執行個體(**不需要建實體**),只能使用私有的建構函式,或者配合靜態建構函式 -一般方法只有該類別實體可以叫用,靜態方法使用類別名稱後大家都可以叫用(公用) ```csharp publicclassNotStaticClass { publicintprice_1; publicvoidgetPrice(){} publicstaticvoidgetPriceStatic(){}//一般類別也可以包含靜態成員 publicstaticprice_0=0; publicDeposit{ get{returnprice_0;} set{price_0=value;} } publicstaticclassStaticClass { publicstaticprice=0; publicstaticvoidgetPrice(){} } ``` ####static變數 ```csharp StaticClassExample_1=newStaticClass(); Example_1.Deposit=100; StaticClassExample_2=newStaticClass(); Example_2.Deposit=120; Console.WriteLine(Example_1.Deposit); Console.WriteLine(Example_2.Deposit); /*Output: 120 120 */ ``` 即使建造了不同物件,變數使用的記憶體空間依然共用,因此對變數值的控管要更加注意。

####static方法類別 nonstatic的方法類別需要先建立物件才能呼叫,static的方法直接呼叫即可;因為程式一開始執行的時候就已經存在。

```csharp //static呼叫方法 intS=Static.price; StaticClass.getPrice() //nonstatic呼叫方法 NotStaticClassNS=newNotStaticClass(); NS.price_1=100; NS.getPriceStatic(); ``` ###this關鍵字 ```this```關鍵字指的是類別的目前執行個體,也用作擴充方法第一個參數的修飾詞。

####Constructor建構式 this最經典的用法便是用在建構式,this關鍵字用來強調當前執行的**主角**,在建構式中以區分跟主角相同名稱的變數傳遞值。

```csharp publicclassEmployee { privatestringalias; privatestringname; publicEmployee(stringname,stringalias) { //Usethistoqualifythemembersoftheclass //insteadoftheconstructorparameters. this.name=name; this.alias=alias; } } ``` ####擴充方法 這邊是this的另一種用法,可以搭配this將物件當作參數傳遞。

```csharp publicstaticclassMyExtensions { publicstaticintWordCount(thisStringstr) //(this隨便一個參數名字) { returnstr.Split(newchar[]{'','.','?'}, StringSplitOptions.RemoveEmptyEntries).Length; } } ``` 在以下的範例中,this後面不加任何名稱即可傳遞,這是因為this本身就代表著該類別物件實體。

```csharp classEmployee { privatestringname; privatestringalias; privatedecimalsalary=3000.00m; //Constructor: publicEmployee(stringname,stringalias) { //Usethistoqualifythefields,nameandalias: this.name=name; this.alias=alias; } //Printingmethod: publicvoidprintEmployee() { Console.WriteLine("Name:{0}\nAlias:{1}",name,alias); //PassingtheobjecttotheCalcTaxmethodbyusingthis: Console.WriteLine("Taxes:{0:C}",Tax.CalcTax(this)); } publicdecimalSalary { get{returnsalary;} } } classTax { publicstaticdecimalCalcTax(EmployeeE) { return0.08m*E.Salary; } } ``` ####宣告索引 在類別中若想使用Array、List等等有關索引子**Indexer**,就可以使用this來從外部呼叫。

```csharp classUserCollection { Dictionaryusers=newDictionary(); publicUserthis[stringname] { get=>(User)users[name]; set=>users[name]=value; } } //usingtheindexer staticvoidMain(string[]args) { varusers=newUserCollection(); //addobjectsusingindexer users["julie"]=newUser("JulieLerman","[email protected]"); users["mark"]=newUser("MarkLettuce","[email protected]"); users["peter"]=newUser("PeterMbanugo","[email protected]"); //obtainanddisplayMark'sdata Console.WriteLine($"MarksEmail:{users["mark"].Email}"); Console.Read(); } ``` [**索引子宣告**](https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/indexers/using-indexers)更多詳細資料可以點連結進去看喔。

##📁命名空間Namespaces **Namespace**有點類似於C++的封包,還記得我們每次在程式前都會加上```usingSystem```嗎?System本身就是一種默認的封包,然後我們在程式執行時將其導入,因此可以使用裡面類別、函式等等(如:```ConsoleWriteLine```) 說了那麼多,所以我們可以自己建立或改寫**Namespace**嗎? 當然可以! ###建立、改寫Namespaces 建立Namespace其實非常簡單,以下有通式的寫法。

註解的部分是當我們需要使用,但卻沒有導入該Namespace時,就需要以該格式使用方法或建立物件。

+建立 這邊需要注意C2的用法,命名相同是可行的,但是其完整的名稱卻不同,總之就是要把巢狀的部分寫出來啦。

```csharp namespaceN1//N1 { classC1//N1.C1 { classC2//N1.C1.C2 { } } namespaceN2//N1.N2 { classC2//N1.N2.C2 { } } } ``` :::info 命名空間位置: 1.```N1```命名空間是全域命名空間的成員。

2.```N2```命名空間是```N1```的成員。

3.```C1```類別是```N1```的成員。

::: +改寫 ```csharp namespaceN1.N2 { classC3//N1.N2.C3 { } } ``` +巢狀Namespace建立物件 若是使用了巢狀Namespace並且需要建立物件,這邊建議在的宣告中將完整名稱全部寫出來,以方便Debug,如:```N1.N2.C2=newNi.N2.C2()```。

不過若是因為各種理由不想寫(**懶**),程式的Default是以全域的class為主。

```csharp namespaceSampleNamespace { classSampleClass { publicvoidSampleMethod() { System.Console.WriteLine( "SampleMethodinsideSampleNamespace"); } } //Createanestednamespace,anddefineanotherclass. namespaceNestedNamespace { classSampleClass { publicvoidSampleMethod() { System.Console.WriteLine( "SampleMethodinsideNestedNamespace"); } } } classProgram { staticvoidMain(string[]args) { //Displays"SampleMethodinsideSampleNamespace." SampleClassouter=newSampleClass(); outer.SampleMethod(); //Displays"SampleMethodinsideSampleNamespace." SampleNamespace.SampleClassouter2= newSampleNamespace.SampleClass(); outer2.SampleMethod(); //Displays"SampleMethodinsideNestedNamespace." NestedNamespace.SampleClassinner= newNestedNamespace.SampleClass(); inner.SampleMethod(); } } } ``` ###使用命名空間 一般而言,使用命名空間別名限定詞```::```來參考命名空間別名,或使用```global::```來參考全域命名空間,以及使用```.```來限定型別或成員。

+改稱 假如全域命名空間中的一個**型別**以另一名稱參考,如:```usingAlias=System.Console;```,此時使用```::```是錯誤的! ```csharp classTestClass { staticvoidMain() { //Error //Alias::WriteLine("Hi"); //OK Alias.WriteLine("Hi"); } } ``` 但若是在全域命名空間之巢狀的**命名空間**即可使用。

```csharp usingforwinforms=System.Drawing; usingforwpf=System.Windows; publicclassConverters { publicstaticforwpf::PointConvert(forwinforms::Pointpoint)=> newforwpf::Point(point.X,point.Y); } ``` +專於導入命名空間(**避免導入非預期類型**) ```::```限定詞可確保其左邊的識別字一律會參考**命名空間(別名)**,即使存在具有相同名稱的型別也一樣。

此時使用```::```是為了使被改稱之全域的System被視為命名空間的改稱,而非型別。

```csharp usingAlias=System; namespaceLibrary { publicclassC:Alias::Exception{} } ``` +結論 使用```::```的情況為目的型強調右邊之識別字為**左側的命名空間**(若於全域則使用global)識別字的方法、型別等等。

× Signin Email Password Forgotpassword or Byclickingbelow,youagreetoourtermsofservice. SigninviaFacebook SigninviaTwitter SigninviaGitHub SigninviaDropbox NewtoHackMD?Signup



請為這篇文章評分?