日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#6.0语言规范(一) 介绍

發布時間:2025/4/9 C# 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#6.0语言规范(一) 介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C#(發音為“See Sharp”)是一種簡單,現代,面向對象,類型安全的編程語言。C#源于C語言系列,對C,C ++和Java程序員來說很熟悉。EC#International將EC#標準化為ECMA-334標準,ISO / IEC標準化為ISO / IEC 23270標準。Microsoft的.NET Framework C#編譯器是這兩個標準的一致性實現。

C#是一種面向對象的語言,但C#還包括對面向組件編程的支持。當代軟件設計越來越依賴于自包含和自描述功能包形式的軟件組件。這些組件的關鍵是它們呈現具有屬性,方法和事件的編程模型;?它們具有提供有關組件的聲明性信息的屬性;?他們合并了自己的文件。C#提供直接支持這些概念的語言結構,使C#成為一種非常自然的語言,可以在其中創建和使用軟件組件。

幾個C#功能有助于構建強大而持久的應用程序:垃圾收集自動回收未使用對象占用的內存;?異常處理提供了一種結構化和可擴展的錯誤檢測和恢復方法;?并且語言的類型安全設計使得無法從未初始化的變量讀取,將數組索引超出其邊界,或者執行未經檢查的類型轉換。

C#有一個統一的類型系統。所有C#類型,包括諸如int和的原始類型double,都從單個根object類型繼承。因此,所有類型共享一組公共操作,并且可以以一致的方式存儲,傳輸和操作任何類型的值。此外,C#支持用戶定義的引用類型和值類型,允許動態分配對象以及輕量級結構的內聯存儲。

為了確保C#程序和庫能夠以兼容的方式隨著時間的推移而發展,C#的設計中的版本控制已經得到了很大的重視。許多編程語言很少關注這個問題,因此,當引入新版本的依賴庫時,使用這些語言編寫的程序會比必要時更頻繁地中斷。直接受版本控制考慮因素影響的C#設計方面包括單獨的virtual和override修飾符,方法重載決策的規則以及對顯式接口成員聲明的支持。

本章的其余部分描述了C#語言的基本功能。雖然后面的章節以面向細節的方式描述了規則和例外,有時甚至是數學方式,但本章的目的是為了清晰和簡潔而犧牲完整性。目的是向讀者提供有助于編寫早期程序和閱讀后續章節的語言的介紹。

Hello , World

“Hello,World”程序傳統上用于介紹編程語言。這是在C#中:

1 using System; 2 3 class Hello 4 { 5 static void Main() { 6 Console.WriteLine("Hello, World"); 7 } 8 }

C#源文件通常具有文件擴展名.cs。假設“Hello,World”程序存儲在文件中hello.cs,可以使用命令行使用Microsoft C#編譯器編譯程序

csc hello.cs 產生一個名為的可執行組件hello.exe。此應用程序運行時產生的輸出是 Hello, World

“Hello,World”程序以using引用System命名空間的指令開頭。命名空間提供了組織C#程序和庫的分層方法。命名空間包含類型和其他命名空間 - 例如,System命名空間包含許多類型,例如Console程序中引用的類,以及許多其他命名空間,例如IO和Collections。一個using引用給定的命名空間指令允許非限定方式使用該命名空間的成員的類型。由于該using指令,該程序可以Console.WriteLine用作速記System.Console.WriteLine。

Hello由“Hello,World”程序聲明的類只有一個成員,名為Main。Main使用static修飾符聲明該方法。雖然實例方法可以使用關鍵字引用特定的封閉對象實例this,但靜態方法在不引用特定對象的情況下操作。按照慣例,名為的靜態方法Main用作程序的入口點。

程序的輸出由命名空間WriteLine中的Console類的方法生成System。此類由.NET Framework類庫提供,默認情況下,它由Microsoft C#編譯器自動引用。請注意,C#本身沒有單獨的運行時庫。相反,.NET Framework是C#的運行時庫。

組織結構

C#中的關鍵組織概念是程序,命名空間,類型,成員和程序集。C#程序由一個或多個源文件組成。程序聲明類型,包含成員,可以組織成命名空間。類和接口是類型的示例。字段,方法,屬性和事件是成員的示例。編譯C#程序時,它們將物理打包到程序集中。程序集通常具有文件擴展名,.exe或者.dll取決于它們是否實現應用程序或庫。

1 using System; 2 3 namespace Acme.Collections 4 { 5 public class Stack 6 { 7 Entry top; 8 9 public void Push(object data) { 10 top = new Entry(top, data); 11 } 12 13 public object Pop() { 14 if (top == null) throw new InvalidOperationException(); 15 object result = top.data; 16 top = top.next; 17 return result; 18 } 19 20 class Entry 21 { 22 public Entry next; 23 public object data; 24 25 public Entry(Entry next, object data) { 26 this.next = next; 27 this.data = data; 28 } 29 } 30 } 31 }

聲明在名為Stack的命名空間中命名的類Acme.Collections。此類的完全限定名稱是Acme.Collections.Stack。該類包含幾個成員:一個名為場top兩個方法命名,Push并Pop,并命名為嵌套類Entry。該Entry班還包含三個成員:一個名為場next,一場名為data和一個構造函數。假設示例的源代碼存儲在文件中acme.cs,命令行

csc /t:library acme.cs

將示例編譯為庫(沒有Main入口點的代碼)并生成一個名為的程序集acme.dll。

程序集包含中間語言(IL)指令形式的可執行代碼,以及元數據形式的符號信息。在執行之前,程序集中的IL代碼將由.NET公共語言運行時的即時(JIT)編譯器自動轉換為特定于處理器的代碼。

因為程序集是包含代碼和元數據的自描述功能單元,所以#includeC#中不需要指令和頭文件。特定程序集中包含的公共類型和成員只需在編譯程序時引用該程序集即可在C#程序中使用。例如,此程序使用程序集中的Acme.Collections.Stack類acme.dll:

1 using System; 2 using Acme.Collections; 3 4 class Test 5 { 6 static void Main() { 7 Stack s = new Stack(); 8 s.Push(1); 9 s.Push(10); 10 s.Push(100); 11 Console.WriteLine(s.Pop()); 12 Console.WriteLine(s.Pop()); 13 Console.WriteLine(s.Pop()); 14 } 15 }

如果程序存儲在文件中test.cs,test.cs則編譯時,acme.dll可以使用編譯器/r選項引用程序集:

csc /r:acme.dll test.cs

這將創建一個名為的可執行程序集test.exe,在運行時會生成輸出:

1 100 2 10 3 1

C#允許將程序的源文本存儲在多個源文件中。編譯多文件C#程序時,所有源文件一起處理,源文件可以自由地相互引用 - 概念上,就好像所有源文件在處理之前被連接成一個大文件一樣。C#中從不需要前向聲明,因為除極少數例外情況外,聲明順序無關緊要。C#不限制源文件僅聲明一個公共類型,也不要求源文件的名稱與源文件中聲明的類型匹配。

類型和變量

C#中有兩種類型:值類型和引用類型。值類型的變量直接包含它們的數據,而引用類型的變量存儲對其數據的引用,后者稱為對象。對于引用類型,兩個變量可以引用同一個對象,因此對一個變量的操作可能會影響另一個變量引用的對象。對于值類型,每個變量都有自己的數據副本,并且一個上的操作不可能影響另一個(除了ref和out參數變量之外)。

C#的值類型進一步分為簡單類型,枚舉類型,結構類型和可空類型,C#的引用類型又分為類類型,接口類型,數組類型和委托類型。

下表概述了C#的類型系統。

類別?描述
價值類型簡單的類型符號整型:sbyte,short,int,long
??無符號整型:byte,ushort,uint,ulong
??Unicode字符:?char
??IEEE浮點:float,double
??高精度十進制:?decimal
??布爾:?bool
?枚舉類型用戶定義的表單類型?enum E {...}
?結構類型用戶定義的表單類型?struct S {...}
?可空類型帶有null值的所有其他值類型的擴展
參考類型類類型所有其他類型的終極基類:?object
??Unicode字符串:?string
??用戶定義的表單類型?class C {...}
?接口類型用戶定義的表單類型?interface I {...}
?數組類型單和多維,例如,int[]和int[,]
?委托類型用戶定義的表單類型,例如?delegate int D(...)

八種積分類型支持有符號或無符號形式的8位,16位,32位和64位值。

兩個浮點類型,float并且double,使用的是32位單精度和64位雙精度IEEE 754格式表示。

該decimal類型是128位數據類型,適用于財務和貨幣計算。

C#的bool類型用于表示布爾值 - 值為true或的值false。

C#中的字符和字符串處理使用Unicode編碼。該char類型表示UTF-16代碼單元,該string類型表示UTF-16代碼單元序列。

下表總結了C#的數字類型。

類別位類型范圍/精度
簽名積分8sbyte-128...127
?16short-32,768...32,767
?32int-2,147,483,648...2,147,483,647
?64long-9,223,372,036,854,775,808...9,223,372,036,854,775,807
無符號積分8byte0...255
?16ushort0...65,535
?32uint0...4,294,967,295
?64ulong0...18,446,744,073,709,551,615
浮點32float1.5×10 ^ -45至3.4×10 ^ 38,7位精度
?64double5.0×10 ^ -324至1.7×10 ^ 308,15位精度
十進制128decimal1.0×10 ^ -28至7.9×10 ^ 28,28位精度

C#程序使用類型聲明來創建新類型。類型聲明指定新類型的名稱和成員。C#的五種類型是用戶可定義的:類類型,結構類型,接口類型,枚舉類型和委托類型。

類類型定義包含數據成員(字段)和函數成員(方法,屬性等)的數據結構。類類型支持單繼承和多態,這是派生類可以擴展和專門化基類的機制。

結構類型類似于類類型,因為它表示具有數據成員和函數成員的結構。但是,與類不同,結構是值類型,不需要堆分配。結構類型不支持用戶指定的繼承,并且所有結構類型都隱式繼承自類型object。

接口類型將合同定義為一組命名的公共函數成員。實現接口的類或結構必須提供接口的函數成員的實現。接口可以從多個基接口繼承,并且類或結構可以實現多個接口。

委托類型表示對具有特定參數列表和返回類型的方法的引用。委托使得可以將方法視為可以分配給變量并作為參數傳遞的實體。委托類似于在其他一些語言中找到的函數指針的概念,但與函數指針不同,委托是面向對象的,類型安全的。

類,結構,接口和委托類型都支持泛型,因此可以使用其他類型對它們進行參數化。

枚舉類型是具有命名常量的不同類型。每個枚舉類型都有一個底層類型,它必須是八種整數類型之一。枚舉類型的值集與基礎類型的值集相同。

C#支持任何類型的單維和多維數組。與上面列出的類型不同,數組類型在使用之前不必聲明。而是通過使用帶方括號的類型名稱來構造數組類型。例如,int[]是一個一維數組int,int[,]是一個二維陣列int,和int[][]是的一維數組的一維陣列int。

可以使用Nullable類型之前也不必聲明它們。對于每個非可空值類型,T存在相應的可空類型T?,其可以保存附加值null。例如,int?是一種可以保存任何32位整數或值的類型null。

C#的類型系統是統一的,任何類型的值都可以被視為一個對象。C#中的每個類型都直接或間接地從object類類型派生,并且object是所有類型的最終基類。只需將值視為類型,即可將引用類型的值視為對象object。值類型的值則通過執行當作對象裝箱和拆箱操作。在以下示例中,將int值轉換為object,然后再轉換回int。

1 using System; 2 3 class Test 4 { 5 static void Main() { 6 int i = 123; 7 object o = i; // Boxing 8 int j = (int)o; // Unboxing 9 } 10 }

當值類型的值轉換為類型時object,將分配一個對象實例(也稱為“框”)來保存該值,并將該值復制到該框中。相反,當object引用轉換為值類型時,將檢查引用的對象是否為正確值類型的框,如果檢查成功,則復制框中的值。

C#的統一類型系統有效地意味著值類型可以“按需”成為對象。由于統一,使用類型的通用庫object可以與引用類型和值類型一起使用。

C#中有幾種變量,包括字段,數組元素,局部變量和參數。變量表示存儲位置,每個變量都有一個類型,用于確定可以在變量中存儲的值,如下表所示。

變量類型可能的內容
不可為空的值類型該確切類型的值
可空值類型空值或該確切類型的值
object空引用,對任何引用類型的對象的引用,或對任何值類型的盒裝值的引用
班級類型空引用,對該類類型的實例的引用,或對從該類類型派生的類的實例的引用
接口類型空引用,對實現該接口類型的類類型實例的引用,或對實現該接口類型的值類型的盒裝值的引用
數組類型空引用,對該數組類型的實例的引用,或對兼容數組類型的實例的引用
委托類型空引用或對該委托類型的實例的引用

表達式

表達式由操作數和運算符構成。表達式的運算符指示要應用于操作數的操作。運營商的例子包括+,-,*,/,和new。操作數的示例包括文字,字段,局部變量和表達式。

當表達式包含多個運算符時,運算符的優先級控制各個運算符的計算順序。例如,表達式x + y * z的計算結果是x + (y * z)因為*運算符的優先級高于+運算符。

大多數運營商都可能過載。運算符重載允許為其中一個或兩個操作數是用戶定義的類或結構類型的操作指定用戶定義的運算符實現。

下表總結了C#的運算符,按從高到低的優先順序列出了運算符類別。同一類別的運營商具有相同的優先權。

類別表達描述
x.m會員訪問權限
?x(...)方法和委托調用
?x[...]數組和索引器訪問
?x++后遞增
?x--后減
?new T(...)對象和委托創建
?new T(...){...}使用初始化程序創建對象
?new {...}匿名對象初始化程序
?new T[...]數組創建
?typeof(T)獲取System.Type對象T
?checked(x)在檢查的上下文中評估表達式
?unchecked(x)在未選中的上下文中評估表達式
?default(T)獲取類型的默認值?T
?delegate {...}匿名函數(匿名方法)
一元+x身分
?-x否定
?!x邏輯否定
?~x按位否定
?++x預增
?--x預減
?(T)x明確轉換x為類型T
?await x異步等待x完成
x * y乘法
?x / y
?x % y
添加劑x + y加法,字符串連接,委托組合
?x - y減法,代表刪除
轉移x << y向左轉
?x >> y向右轉
關系和類型測試x < y少于
?x > y比...更棒
?x <= y小于等于
?x >= y大于或等于
?x is Ttrue如果x是T,false則返回,否則
?x as T返回x類型為T,或者null如果x不是T
平等x == y等于
?x != y不相等
邏輯和x & y整數按位AND,布爾邏輯AND
邏輯異或x ^ y整數按位XOR,布爾邏輯XOR
邏輯或`X和`
有條件的ANDx && y評估y僅x是true
條件OR`X?
無法合并X ?? y否則,評估yif?x是否nullx
條件x ? y : z評估y如果x是true,z如果x是false
作業或匿名功能x = y分配
?x op= y復合賦值;?支持的運算符是*=?/=?%=?+=?-=?<<=?>>=?&=?^=`
?(T x) => y匿名函數(lambda表達式)

聲明

程序的動作用語句表示。C#支持幾種不同類型的語句,其中一些語句是根據嵌入語句定義的。

一個塊允許在一個單一的語句允許上下文中編寫多條語句。一個塊由一個在分隔符{和}。之間寫的語句列表組成。

聲明語句用于聲明局部變量和常量。

表達式語句用于計算表達式??捎米髡Z句的表達式包括方法調用,使用new運算符的對象分配,使用賦值=和復合賦值運算符,使用++和--運算符和await表達式的遞增和遞減操作。

Selection語句用于根據某個表達式的值選擇一些可能的語句來執行。在這組中是if和switch語句。

迭代語句用于重復執行嵌入語句。在這組是while,do,for,和foreach語句。

跳轉語句用于傳輸控制。在這組是break,continue,goto,throw,return,和yield語句。

該try...?catch語句用于捕獲在塊的執行期間發生的異常,并try...?finally語句用于指定始終執行終止代碼,是否發生異常。

該checked和unchecked語句用于控制整型算術運算和轉換的溢出檢查上下文。

該lock語句用于獲取給定對象的互斥鎖,執行語句,然后釋放鎖。

該using語句用于獲取資源,執行語句,然后處置該資源。

以下是各種陳述的示例

局部變量聲明

1 static void Main() { 2 int a; 3 int b = 2, c = 3; 4 a = 1; 5 Console.WriteLine(a + b + c); 6 }

本地常量聲明

1 static void Main() { 2 const float pi = 3.1415927f; 3 const int r = 25; 4 Console.WriteLine(pi * r * r); 5 }

if?聲明

1 static void Main(string[] args) { 2 if (args.Length == 0) { 3 Console.WriteLine("No arguments"); 4 } 5 else { 6 Console.WriteLine("One or more arguments"); 7 } 8 }

switch?聲明

1 static void Main(string[] args) { 2 int n = args.Length; 3 switch (n) { 4 case 0: 5 Console.WriteLine("No arguments"); 6 break; 7 case 1: 8 Console.WriteLine("One argument"); 9 break; 10 default: 11 Console.WriteLine("{0} arguments", n); 12 break; 13 } 14 }

while?聲明

1 static void Main(string[] args) { 2 int i = 0; 3 while (i < args.Length) { 4 Console.WriteLine(args[i]); 5 i++; 6 } 7 }

do?聲明

1 static void Main() { 2 string s; 3 do { 4 s = Console.ReadLine(); 5 if (s != null) Console.WriteLine(s); 6 } while (s != null); 7 }

for?聲明

1 static void Main(string[] args) { 2 for (int i = 0; i < args.Length; i++) { 3 Console.WriteLine(args[i]); 4 } 5 }

foreach?聲明

1 static void Main(string[] args) { 2 foreach (string s in args) { 3 Console.WriteLine(s); 4 } 5 }

break?聲明

1 static void Main() { 2 while (true) { 3 string s = Console.ReadLine(); 4 if (s == null) break; 5 Console.WriteLine(s); 6 } 7 }

continue?聲明

1 static void Main(string[] args) { 2 for (int i = 0; i < args.Length; i++) { 3 if (args[i].StartsWith("/")) continue; 4 Console.WriteLine(args[i]); 5 } 6 }

goto?聲明

1 static void Main(string[] args) { 2 int i = 0; 3 goto check; 4 loop: 5 Console.WriteLine(args[i++]); 6 check: 7 if (i < args.Length) goto loop; 8 }

return?聲明

1 static int Add(int a, int b) { 2 return a + b; 3 } 4 5 static void Main() { 6 Console.WriteLine(Add(1, 2)); 7 return; 8 }

yield?聲明

1 static IEnumerable<int> Range(int from, int to) { 2 for (int i = from; i < to; i++) { 3 yield return i; 4 } 5 yield break; 6 } 7 8 static void Main() { 9 foreach (int x in Range(-10,10)) { 10 Console.WriteLine(x); 11 } 12 }

throw和try 聲明

1 static double Divide(double x, double y) { 2 if (y == 0) throw new DivideByZeroException(); 3 return x / y; 4 } 5 6 static void Main(string[] args) { 7 try { 8 if (args.Length != 2) { 9 throw new Exception("Two numbers required"); 10 } 11 double x = double.Parse(args[0]); 12 double y = double.Parse(args[1]); 13 Console.WriteLine(Divide(x, y)); 14 } 15 catch (Exception e) { 16 Console.WriteLine(e.Message); 17 } 18 finally { 19 Console.WriteLine("Good bye!"); 20 } 21 }

checked和unchecked 聲明

1 static void Main() { 2 int i = int.MaxValue; 3 checked { 4 Console.WriteLine(i + 1); // Exception 5 } 6 unchecked { 7 Console.WriteLine(i + 1); // Overflow 8 } 9 }

lock?聲明

1 class Account 2 { 3 decimal balance; 4 public void Withdraw(decimal amount) { 5 lock (this) { 6 if (amount > balance) { 7 throw new Exception("Insufficient funds"); 8 } 9 balance -= amount; 10 } 11 } 12 }

using?聲明

1 static void Main() { 2 using (TextWriter w = File.CreateText("test.txt")) { 3 w.WriteLine("Line one"); 4 w.WriteLine("Line two"); 5 w.WriteLine("Line three"); 6 } 7 }

類和對象

類是C#類型中最基本的類。類是一種將狀態(字段)和操作(方法和其他函數成員)組合在一個單元中的數據結構。類為動態創建的類實例提供定義,也稱為對象。類支持繼承和多態,這是派生類可以擴展和專門化基類的機制。

使用類聲明創建新類。類聲明以標頭開頭,該標頭指定類的屬性和修飾符,類的名稱,基類(如果給定)以及類實現的接口。標題后跟類主體,它由在分隔符{和分隔符之間寫入的成員聲明列表組成}。

以下是一個名為的簡單類的聲明Point:

1 public class Point 2 { 3 public int x, y; 4 5 public Point(int x, int y) { 6 this.x = x; 7 this.y = y; 8 } 9 }

類的實例是使用new運算符創建的,該運算符為新實例分配內存,調用構造函數初始化實例,并返回對實例的引用。以下語句創建兩個Point對象,并在兩個變量中存儲對這些對象的引用:

1 Point p1 = new Point(0, 0); 2 Point p2 = new Point(10, 20);

當對象不再使用時,對象占用的內存將自動回收。在C#中顯式釋放對象既不必要也不可能。

類的成員

類的成員是靜態成員或實例成員。靜態成員屬于類,實例成員屬于對象(類的實例)。

下表概述了類可以包含的成員類型。

會員描述
常量與類關聯的常量值
字段班級的變量
方法可以由班級執行的計算和操作
屬性與讀取和編寫類的命名屬性相關的操作
索引與索引類的實例(如數組)相關聯的操作
活動可以由類生成的通知
運營商類支持的轉換和表達式運算符
構造函數初始化類的實例或類本身所需的操作
驅逐艦在類的實例之前執行的操作將被永久丟棄
類型類聲明的嵌套類型

輔助功能

類的每個成員都有一個關聯的輔助功能,它控制能夠訪問該成員的程序文本區域。可訪問性有五種可能的形式。這些總結在下表中。

無障礙含義
public訪問不受限制
protected訪問僅限于此類或從此類派生的類
internal訪問僅限于此計劃
protected internal訪問僅限于此程序或從此類派生的類
private訪問僅限于此課程

輸入參數

類定義可以通過使用包含類型參數名稱列表的尖括號跟隨類名來指定一組類型參數。類型參數可以在類聲明的主體中使用,以定義類的成員。在以下示例中,類型參數Pair是TFirst和TSecond:

1 public class Pair<TFirst,TSecond> 2 { 3 public TFirst First; 4 public TSecond Second; 5 }

聲明為采用類型參數的類類型稱為泛型類類型。結構,接口和委托類型也可以是通用的。

使用泛型類時,必須為每個類型參數提供類型參數:

1 Pair<int,string> pair = new Pair<int,string> { First = 1, Second = "two" }; 2 int i = pair.First; // TFirst is int 3 string s = pair.Second; // TSecond is string

提供類型參數的泛型類型(Pair<int,string>如上所述)稱為構造類型。

基類

類聲明可以通過跟隨類名和類型參數以及冒號和基類的名稱來指定基類。省略基類規范與從類型派生相同object。在以下示例中,基類為Point3Dis?Point,基類Point為object:

1 public class Point 2 { 3 public int x, y; 4 5 public Point(int x, int y) { 6 this.x = x; 7 this.y = y; 8 } 9 } 10 11 public class Point3D: Point 12 { 13 public int z; 14 15 public Point3D(int x, int y, int z): base(x, y) { 16 this.z = z; 17 } 18 }

類繼承其基類的成員。繼承意味著類隱式包含其基類的所有成員,但實例和靜態構造函數以及基類的析構函數除外。派生類可以向其繼承的成員添加新成員,但不能刪除繼承成員的定義。在前面的例子中,Point3D繼承x并y從領域Point,每一個Point3D實例都包含三個字段,x,y,和z。

存在從類類型到其任何基類類型的隱式轉換。因此,類類型的變量可以引用該類的實例或任何派生類的實例。例如,給定前面的類聲明,類型的變量Point可以引用a?Point或a?Point3D:

1 Point a = new Point(10, 20); 2 Point b = new Point3D(10, 20, 30);

字段

字段是與類或類的實例關聯的變量。

使用static修飾符聲明的字段定義靜態字段。靜態字段只標識一個存儲位置。無論創建了多少個類實例,都只有一個靜態字段的副本。

聲明沒有static修飾符的字段定義實例字段。類的每個實例都包含該類的所有實例字段的單獨副本。

在下面的例子中,每個實例Color類具有的一個單獨的副本r,g和b實例字段,但只有一個的副本Black,White,Red,Green,和Blue靜態字段:

1 public class Color 2 { 3 public static readonly Color Black = new Color(0, 0, 0); 4 public static readonly Color White = new Color(255, 255, 255); 5 public static readonly Color Red = new Color(255, 0, 0); 6 public static readonly Color Green = new Color(0, 255, 0); 7 public static readonly Color Blue = new Color(0, 0, 255); 8 private byte r, g, b; 9 10 public Color(byte r, byte g, byte b) { 11 this.r = r; 12 this.g = g; 13 this.b = b; 14 } 15 }

如前面的示例所示,可以使用修飾符聲明只讀字段readonly。對readonly字段的賦值只能作為字段聲明的一部分或在同一類的構造函數中出現。

方法

甲方法是實現可以由對象或類執行的計算或操作的部件。通過類訪問靜態方法。通過類的實例訪問實例方法。

方法有一個(可能是空的)參數列表,它表示傳遞給方法的值或變量引用,以及一個返回類型,它指定方法計算和返回的值的類型。方法的返回類型是void它不返回值。

與類型類似,方法也可能有一組類型參數,在調用方法時必須為其指定類型參數。與類型不同,類型參數通??梢詮姆椒ㄕ{用的參數推斷出來,不需要明確給出。

方法的簽名在聲明方法的類中必須是唯一的。方法的簽名包括方法的名稱,類型參數的數量以及數量,修飾符和參數類型。方法的簽名不包括返回類型。

參數

參數用于將值或變量引用傳遞給方法。方法的參數從調用方法時指定的參數中獲取其實際值。有四種參數:值參數,參考參數,輸出參數和參數數組。

甲值參數被用于輸入參數的傳遞。值參數對應于一個局部變量,該局部變量從為參數傳遞的參數中獲取其初始值。對value參數的修改不會影響為參數傳遞的參數。

通過指定默認值,可以選擇值參數,以便可以省略相應的參數。

甲基準參數是用于輸入和輸出參數的傳遞。為參考參數傳遞的參數必須是變量,并且在執行方法期間,引用參數表示與參數變量相同的存儲位置。使用ref修飾符聲明引用參數。以下示例顯示了ref參數的使用。

1 using System; 2 3 class Test 4 { 5 static void Swap(ref int x, ref int y) { 6 int temp = x; 7 x = y; 8 y = temp; 9 } 10 11 static void Main() { 12 int i = 1, j = 2; 13 Swap(ref i, ref j); 14 Console.WriteLine("{0} {1}", i, j); // Outputs "2 1" 15 } 16 }

一個輸出參數被用于輸出參數的傳遞。輸出參數類似于引用參數,除了調用者提供的參數的初始值不重要。使用out修飾符聲明輸出參數。以下示例顯示了out參數的使用。

1 using System; 2 3 class Test 4 { 5 static void Divide(int x, int y, out int result, out int remainder) { 6 result = x / y; 7 remainder = x % y; 8 } 9 10 static void Main() { 11 int res, rem; 12 Divide(10, 3, out res, out rem); 13 Console.WriteLine("{0} {1}", res, rem); // Outputs "3 1" 14 } 15 }

甲參數數組允許將傳遞給方法的參數個數可變。使用params修飾符聲明參數數組。只有方法的最后一個參數可以是參數數組,參數數組的類型必須是一維數組類型。該類的Write和WriteLine方法System.Console是參數數組使用的很好的例子。它們聲明如下。

1 public class Console 2 { 3 public static void Write(string fmt, params object[] args) {...} 4 public static void WriteLine(string fmt, params object[] args) {...} 5 ... 6 }

在使用參數數組的方法中,參數數組的行為與數組類型的常規參數完全相同。但是,在使用參數數組調用方法時,可以傳遞參數數組類型的單個參數或參數數組的元素類型的任意數量的參數。在后一種情況下,將使用給定的參數自動創建和初始化數組實例。這個例子

1 Console.WriteLine("x={0} y={1} z={2}", x, y, z);

相當于寫下面的內容。

1 string s = "x={0} y={1} z={2}"; 2 object[] args = new object[3]; 3 args[0] = x; 4 args[1] = y; 5 args[2] = z; 6 Console.WriteLine(s, args);

方法體和局部變量

方法的主體指定在調用方法時要執行的語句。

方法體可以聲明特定于方法調用的變量。這些變量稱為局部變量。局部變量聲明指定類型名稱,變量名稱以及可能的初始值。以下示例聲明一個i初始值為零的局部變量和一個j沒有初始值的局部變量。

1 using System; 2 3 class Squares 4 { 5 static void Main() { 6 int i = 0; 7 int j; 8 while (i < 10) { 9 j = i * i; 10 Console.WriteLine("{0} x {0} = {1}", i, j); 11 i = i + 1; 12 } 13 } 14 }

C#需要在可以獲得其值之前明確賦值。例如,如果前面的聲明i不包含初始值,則編譯器將報告后續用法的錯誤,i因為i在程序中的那些點處不會明確分配。

方法可以使用return語句將控制權返回給其調用者。在返回的方法中void,return語句不能指定表達式。在返回非的方法中void,return語句必須包含計算返回值的表達式。

靜態和實例方法

使用static修飾符聲明的方法是靜態方法。靜態方法不能在特定實例上運行,只能直接訪問靜態成員。

聲明沒有static修飾符的方法是實例方法。實例方法在特定實例上運行,并且可以訪問靜態成員和實例成員??梢燥@式訪問調用實例方法的實例this。this在靜態方法中引用是錯誤的。

以下Entity類具有靜態成員和實例成員。

1 class Entity 2 { 3 static int nextSerialNo; 4 int serialNo; 5 6 public Entity() { 7 serialNo = nextSerialNo++; 8 } 9 10 public int GetSerialNo() { 11 return serialNo; 12 } 13 14 public static int GetNextSerialNo() { 15 return nextSerialNo; 16 } 17 18 public static void SetNextSerialNo(int value) { 19 nextSerialNo = value; 20 } 21 }

每個Entity實例都包含一個序列號(可能還有其他一些未在此處顯示的信息)。的Entity構造(類似于實例方法)初始化與下一個可用的序號新實例。因為構造函數是實例成員,所以允許訪問serialNo實例字段和nextSerialNo靜態字段。

在GetNextSerialNo與SetNextSerialNo靜態方法可以訪問nextSerialNo靜態字段,但是對他們直接訪問這將是一個錯誤serialNo實例字段。

以下示例顯示了Entity該類的用法。

1 using System; 2 3 class Test 4 { 5 static void Main() { 6 Entity.SetNextSerialNo(1000); 7 Entity e1 = new Entity(); 8 Entity e2 = new Entity(); 9 Console.WriteLine(e1.GetSerialNo()); // Outputs "1000" 10 Console.WriteLine(e2.GetSerialNo()); // Outputs "1001" 11 Console.WriteLine(Entity.GetNextSerialNo()); // Outputs "1002" 12 } 13 }

請注意,在類上調用SetNextSerialNo和GetNextSerialNo靜態方法,而在類的GetSerialNo實例上調用實例方法。

虛方法,覆蓋和抽象方法

當實例方法聲明包含virtual修飾符時,該方法被稱為虛方法。當不存在virtual修飾符時,該方法被稱為非虛方法。

調用虛方法時,進行該調用的實例的運行時類型決定了要調用的實際方法實現。在非虛方法調用中,實例的編譯時類型是決定因素。

可以在派生類中重寫虛方法。當實例方法聲明包含override修飾符時,該方法將覆蓋具有相同簽名的繼承虛擬方法。虛擬方法聲明引入了新方法,而覆蓋方法聲明通過提供該方法的新實現來專門化現有的繼承虛擬方法。

一個抽象的方法是沒有實現一個虛擬的方法。使用abstract修飾符聲明抽象方法,并且只允許在聲明的類中使用abstract。必須在每個非抽象派生類中重寫抽象方法。

下面的示例聲明一個抽象類,Expression,它代表一個表達式樹節點和三個派生類Constant,VariableReference以及Operation,它實現了常量,變量引用和算術運算表達式樹的節點。(這類似于,但不要與表達式樹類型中引入的表達式樹類型混淆)。

1 using System; 2 using System.Collections; 3 4 public abstract class Expression 5 { 6 public abstract double Evaluate(Hashtable vars); 7 } 8 9 public class Constant: Expression 10 { 11 double value; 12 13 public Constant(double value) { 14 this.value = value; 15 } 16 17 public override double Evaluate(Hashtable vars) { 18 return value; 19 } 20 } 21 22 public class VariableReference: Expression 23 { 24 string name; 25 26 public VariableReference(string name) { 27 this.name = name; 28 } 29 30 public override double Evaluate(Hashtable vars) { 31 object value = vars[name]; 32 if (value == null) { 33 throw new Exception("Unknown variable: " + name); 34 } 35 return Convert.ToDouble(value); 36 } 37 } 38 39 public class Operation: Expression 40 { 41 Expression left; 42 char op; 43 Expression right; 44 45 public Operation(Expression left, char op, Expression right) { 46 this.left = left; 47 this.op = op; 48 this.right = right; 49 } 50 51 public override double Evaluate(Hashtable vars) { 52 double x = left.Evaluate(vars); 53 double y = right.Evaluate(vars); 54 switch (op) { 55 case '+': return x + y; 56 case '-': return x - y; 57 case '*': return x * y; 58 case '/': return x / y; 59 } 60 throw new Exception("Unknown operator"); 61 } 62 }

前四個類可用于對算術表達式進行建模。例如,使用這些類的實例,表達式x + 3可以表示如下。

1 Expression e = new Operation( 2 new VariableReference("x"), 3 '+', 4 new Constant(3));

調用實例的Evaluate方法Expression來評估給定的表達式并生成一個double值。該方法將參數a作為參數Hashtable包含變量名稱(作為條目的鍵)和值(作為條目的值)。該Evaluate方法是一種虛擬抽象方法,這意味著非抽象派生類必須覆蓋它以提供實際實現。

一個Constant人的實現Evaluate簡單地返回存儲的常量。一個VariableReference實現在哈希表中查找變量名并返回結果值。一個Operation實現首先評估左右操作數(通過遞歸調用它們的Evaluate方法),然后執行給定的算術運算。

以下程序使用Expression類來計算x * (y + 2)不同值x和的表達式y。

1 using System; 2 using System.Collections; 3 4 class Test 5 { 6 static void Main() { 7 Expression e = new Operation( 8 new VariableReference("x"), 9 '*', 10 new Operation( 11 new VariableReference("y"), 12 '+', 13 new Constant(2) 14 ) 15 ); 16 Hashtable vars = new Hashtable(); 17 vars["x"] = 3; 18 vars["y"] = 5; 19 Console.WriteLine(e.Evaluate(vars)); // Outputs "21" 20 vars["x"] = 1.5; 21 vars["y"] = 9; 22 Console.WriteLine(e.Evaluate(vars)); // Outputs "16.5" 23 } 24 }

方法重載

方法重載允許同一類中的多個方法具有相同的名稱,只要它們具有唯一的簽名即可。在編譯重載方法的調用時,編譯器使用重載決策來確定要調用的特定方法。如果找不到單個最佳匹配,則重載決策會找到最匹配參數的一種方法或報告錯誤。以下示例顯示了有效的重載決策。Main方法中每次調用的注釋都顯示實際調用的方法。

1 class Test 2 { 3 static void F() { 4 Console.WriteLine("F()"); 5 } 6 7 static void F(object x) { 8 Console.WriteLine("F(object)"); 9 } 10 11 static void F(int x) { 12 Console.WriteLine("F(int)"); 13 } 14 15 static void F(double x) { 16 Console.WriteLine("F(double)"); 17 } 18 19 static void F<T>(T x) { 20 Console.WriteLine("F<T>(T)"); 21 } 22 23 static void F(double x, double y) { 24 Console.WriteLine("F(double, double)"); 25 } 26 27 static void Main() { 28 F(); // Invokes F() 29 F(1); // Invokes F(int) 30 F(1.0); // Invokes F(double) 31 F("abc"); // Invokes F(object) 32 F((double)1); // Invokes F(double) 33 F((object)1); // Invokes F(object) 34 F<int>(1); // Invokes F<T>(T) 35 F(1, 1); // Invokes F(double, double) 36 } 37 }

如示例所示,始終可以通過將參數顯式地轉換為確切的參數類型和/或顯式提供類型參數來選擇特定方法。

其他函數成員

包含可執行代碼的成員統稱為類的函數成員。上一節描述了方法,它們是函數成員的主要類型。本節介紹C#支持的其他類型的函數成員:構造函數,屬性,索引器,事件,運算符和析構函數。

以下代碼顯示了一個名為的泛型類List<T>,它實現了一個可增長的對象列表。該類包含幾種最常見的函數成員的幾個示例。

1 public class List<T> { 2 // Constant... 3 const int defaultCapacity = 4; 4 5 // Fields... 6 T[] items; 7 int count; 8 9 // Constructors... 10 public List(int capacity = defaultCapacity) { 11 items = new T[capacity]; 12 } 13 14 // Properties... 15 public int Count { 16 get { return count; } 17 } 18 public int Capacity { 19 get { 20 return items.Length; 21 } 22 set { 23 if (value < count) value = count; 24 if (value != items.Length) { 25 T[] newItems = new T[value]; 26 Array.Copy(items, 0, newItems, 0, count); 27 items = newItems; 28 } 29 } 30 } 31 32 // Indexer... 33 public T this[int index] { 34 get { 35 return items[index]; 36 } 37 set { 38 items[index] = value; 39 OnChanged(); 40 } 41 } 42 43 // Methods... 44 public void Add(T item) { 45 if (count == Capacity) Capacity = count * 2; 46 items[count] = item; 47 count++; 48 OnChanged(); 49 } 50 protected virtual void OnChanged() { 51 if (Changed != null) Changed(this, EventArgs.Empty); 52 } 53 public override bool Equals(object other) { 54 return Equals(this, other as List<T>); 55 } 56 static bool Equals(List<T> a, List<T> b) { 57 if (a == null) return b == null; 58 if (b == null || a.count != b.count) return false; 59 for (int i = 0; i < a.count; i++) { 60 if (!object.Equals(a.items[i], b.items[i])) { 61 return false; 62 } 63 } 64 return true; 65 } 66 67 // Event... 68 public event EventHandler Changed; 69 70 // Operators... 71 public static bool operator ==(List<T> a, List<T> b) { 72 return Equals(a, b); 73 } 74 public static bool operator !=(List<T> a, List<T> b) { 75 return !Equals(a, b); 76 } 77 }

構造函數

C#支持實例和靜態構造函數。一個實例構造函數是實現初始化類實例所需操作的成員。一個靜態構造函數是實現初始化類本身是第一次加載時,需要操作的成員。

構造函數被聲明為一個沒有返回類型且與包含類名稱相同的方法。如果構造函數聲明包含static修飾符,則它聲明一個靜態構造函數。否則,它聲明一個實例構造函數。

實例構造函數可以重載。例如,List<T>該類聲明了兩個實例構造函數,一個沒有參數,另一個帶int參數。使用new運算符調用實例構造函數。以下語句List<string>使用類的每個構造函數分配兩個實例List。

1 List<string> list1 = new List<string>(); 2 List<string> list2 = new List<string>(10);

與其他成員不同,實例構造函數不是繼承的,并且除了在類中實際聲明的實例之外,類沒有實例構造函數。如果沒有為類提供實例構造函數,則會自動提供沒有參數的空構造函數。

屬性

屬性是字段的自然擴展。兩者都是具有關聯類型的命名成員,訪問字段和屬性的語法是相同的。但是,與字段不同,屬性不表示存儲位置。相反,屬性具有訪問器,用于指定在讀取或寫入值時要執行的語句。

一個屬性被聲明像場,除了聲明與結束get存取和/或set分隔符之間寫入存取{和}代替分號結尾。具有get訪問者和set訪問者的屬性是讀寫屬性,只有get訪問者的屬性是只讀屬性,只有set訪問者的屬性是只寫屬性。

甲get訪問對應于具有屬性類型的返回值的參數方法。除了作為賦值的目標之外,在表達式中引用屬性時,將get調用屬性的訪問者來計算屬性的值。

甲set存取對應于與命名的單個參數的方法value和無返回類型。當屬性被作為賦值的目標或作為操作數引用++或--,所述set訪問器與提供新值的參數。

在List<T>類聲明了兩個屬性,Count和Capacity,這是只讀和讀寫,分別。以下是使用這些屬性的示例。

1 List<string> names = new List<string>(); 2 names.Capacity = 100; // Invokes set accessor 3 int i = names.Count; // Invokes get accessor 4 int j = names.Capacity; // Invokes get accessor

與字段和方法類似,C#支持實例屬性和靜態屬性。使用static修飾符聲明靜態屬性,并在沒有它的情況下聲明實例屬性。

屬性的訪問者可以是虛擬的。當屬性聲明包含virtual,abstract或override改性劑,它適用于該屬性的訪問(一個或多個)。

索引

一個分度器是使得對象以相同的方式作為數組要索引的部件。索引器的聲明相似,但該成員的名稱屬性this,然后分隔符之間的參數列表[和]。參數在索引器的訪問器中可用。與屬性類似,索引器可以是讀寫,只讀和只寫,索引器的訪問器可以是虛擬的。

在List類聲明了單個讀寫索引器接受一個int參數。索引器可以List使用int值索引實例。例如

1 List<string> names = new List<string>(); 2 names.Add("Liz"); 3 names.Add("Martha"); 4 names.Add("Beth"); 5 for (int i = 0; i < names.Count; i++) { 6 string s = names[i]; 7 names[i] = s.ToUpper(); 8 }

索引器可以重載,這意味著只要參數的數量或類型不同,類就可以聲明多個索引器。

事件

一個事件是一種使類或對象,以提供通知的成員。事件聲明為字段,但聲明包含event關鍵字且類型必須是委托類型。

在聲明事件成員的類中,事件的行為就像委托類型的字段(假設事件不是抽象的,并且不聲明訪問者)。該字段存儲對委托的引用,該委托表示已添加到事件的事件處理程序。如果沒有事件句柄,則該字段為null。

在List<T>類聲明了一個事件成員叫Changed,這預示著一個新的項目已被添加到列表中。該Changed事件由OnChangedvirtual方法引發,該方法首先檢查事件是否為null(意味著不存在處理程序)。提出事件的概念恰好等同于調用事件所代表的委托 - 因此,沒有用于引發事件的特殊語言結構。

客戶端通過事件處理程序對事件做出反應。事件處理程序使用+=操作員連接,并使用-=操作員刪除。以下示例將事件處理程序附加到a的Changed事件List<string>。

1 using System; 2 3 class Test 4 { 5 static int changeCount; 6 7 static void ListChanged(object sender, EventArgs e) { 8 changeCount++; 9 } 10 11 static void Main() { 12 List<string> names = new List<string>(); 13 names.Changed += new EventHandler(ListChanged); 14 names.Add("Liz"); 15 names.Add("Martha"); 16 names.Add("Beth"); 17 Console.WriteLine(changeCount); // Outputs "3" 18 } 19 }

對于需要控制事件的底層存儲的高級方案,事件聲明可以顯式提供add和remove訪問,這有點類似于set屬性的訪問者。

運算符

操作數是定義施加特定表達式運算符一類的實例的含義構件。可以定義三種運算符:一元運算符,二元運算符和轉換運算符。必須將所有運算符聲明為public和static。

在List<T>類聲明了兩個運算operator==和operator!=,從而賦予了新的含義應用于那些運營商的表達List情況。具體來說,運算符定義兩個List<T>實例的相等性,即使用它們的Equals方法比較每個包含的對象。以下示例使用==運算符比較兩個List<int>實例。

1 using System; 2 3 class Test 4 { 5 static void Main() { 6 List<int> a = new List<int>(); 7 a.Add(1); 8 a.Add(2); 9 List<int> b = new List<int>(); 10 b.Add(1); 11 b.Add(2); 12 Console.WriteLine(a == b); // Outputs "True" 13 b.Add(3); 14 Console.WriteLine(a == b); // Outputs "False" 15 } 16 }

第一個Console.WriteLine輸出True是因為兩個列表包含相同數量的對象,它們具有相同順序的相同值。如果List<T>沒有定義operator==,第一個Console.WriteLine將有輸出False因為a并b引用不同的List<int>實例。

析構函數

析構函數是一種用于實現銷毀一個類的實例所需操作的部件。析構函數不能包含參數,它們不能具有可訪問性修飾符,也不能顯式調用它們。在垃圾回收期間自動調用實例的析構函數。

允許垃圾收集器在決定何時收集對象和運行析構函數時有很大的自由度。具體來說,析構函數調用的時間不是確定性的,并且可以在任何線程上執行析構函數。由于這些原因和其他原因,只有在沒有其他解決方案可行時,類才應實現析構函數。

該using陳述提供了一種更好的對象破壞方法。

結構

與類一樣,結構體是可以包含數據成員和函數成員的數據結構,但與類不同,結構體是值類型,不需要堆分配。結構類型的變量直接存儲結構的數據,而類類型的變量存儲對動態分配的對象的引用。結構類型不支持用戶指定的繼承,并且所有結構類型都隱式繼承自類型object。

結構對于具有值語義的小型數據結構特別有用。復數,坐標系中的點或字典中的鍵值對都是結構的好例子。對小型數據結構使用結構而不是類可以使應用程序執行的內存分配數量產生很大差異。例如,以下程序創建并初始化100個點的數組。通過Point實現為類,實例化101個單獨的對象 - 一個用于數組,一個用于100個元素。

1 class Point 2 { 3 public int x, y; 4 5 public Point(int x, int y) { 6 this.x = x; 7 this.y = y; 8 } 9 } 10 11 class Test 12 { 13 static void Main() { 14 Point[] points = new Point[100]; 15 for (int i = 0; i < 100; i++) points[i] = new Point(i, i); 16 } 17 }

另一種方法是制作Point一個結構。

1 struct Point 2 { 3 public int x, y; 4 5 public Point(int x, int y) { 6 this.x = x; 7 this.y = y; 8 } 9 }

現在,只實例化一個對象 - 數組的對象 -?Point實例以串聯方式存儲在數組中。

使用new運算符調用Struct構造函數,但這并不意味著正在分配內存。結構構造函數只是返回結構值本身(通常在堆棧上的臨時位置),而不是動態分配對象并返回對它的引用,然后根據需要復制該值。

對于類,兩個變量可以引用同一個對象,因此對一個變量的操作可能會影響另一個變量引用的對象。對于結構體,變量每個都有自己的數據副本,并且對一個變量的操作不可能影響另一個。例如,以下代碼片段生成的輸出取決于Point是類還是結構。

1 Point a = new Point(10, 10); 2 Point b = a; 3 a.x = 20; 4 Console.WriteLine(b.x);

果Point是類,則輸出是20因為a并b引用相同的對象。如果Point是結構,則輸出是10因為賦值a將b創建值的副本,并且此副本不受后續賦值的影響a.x。

前面的例子強調了結構的兩個局限性。首先,復制整個結構通常比復制對象引用效率低,因此對于結構而言,賦值和值參數傳遞可能比使用引用類型更昂貴。其次,除了ref和out參數之外,不可能創建對結構的引用,結構在許多情況下排除了它們的用法。

數組

一個陣列是一種數據結構,它包含的一定數量的通過計算索引訪問的變量。包含在數組中的變量(也稱為數組的元素)都是相同的類型,這種類型稱為數組的元素類型。

數組類型是引用類型,數組變量的聲明只是為數組實例的引用留出空間。實際的數組實例是在運行時使用new運算符動態創建的。該new操作指定新數組實例的長度,然后在實例的生存期內固定該實例的長度。數組的元素的索引范圍從0到Length - 1。的new操作者自動初始化數組的默認值,其中,例如,對所有的數字類型和零元素null的所有引用類型。

以下示例創建int元素數組,初始化數組,并打印出數組的內容。

1 using System; 2 3 class Test 4 { 5 static void Main() { 6 int[] a = new int[10]; 7 for (int i = 0; i < a.Length; i++) { 8 a[i] = i * i; 9 } 10 for (int i = 0; i < a.Length; i++) { 11 Console.WriteLine("a[{0}] = {1}", i, a[i]); 12 } 13 } 14 }

此示例在單維數組上創建和操作。C#還支持多維數組。數組類型的維數(也稱為數組類型的等級)是一加上在數組類型的方括號之間寫入的逗號數。以下示例分配一維,二維和三維數組。

1 int[] a1 = new int[10]; 2 int[,] a2 = new int[10, 5]; 3 int[,,] a3 = new int[10, 5, 2];

該a1數組包含10個元素,該a2數組包含50(10×5)個元素,該a3數組包含100(10×5×2)個元素。

數組的元素類型可以是任何類型,包括數組類型。具有數組類型元素的數組有時稱為鋸齒狀數組,因為元素數組的長度不必全部相同。以下示例分配一組數組int:

1 int[][] a = new int[3][]; 2 a[0] = new int[10]; 3 a[1] = new int[5]; 4 a[2] = new int[20];

第一行創建一個包含三個元素的數組,每個元素都有一個類型int[],每個元素的初始值都是null。隨后的行然后通過引用不同長度的各個數組實例來初始化這三個元素。

的new操作者允許使用指定的數組元素的初始值數組初始化,這是分隔符之間寫入表達式列表{和}。以下示例int[]使用三個元素分配和初始化a?。

int[] a = new int[] {1, 2, 3};

請注意,數組的長度是從{和之間的表達式數推斷出來的}。可以進一步縮短局部變量和字段聲明,以便不必重新調整數組類型。

int[] a = {1, 2, 3};

前面的兩個示例都等同于以下內容:

1 int[] t = new int[3]; 2 t[0] = 1; 3 t[1] = 2; 4 t[2] = 3; 5 int[] a = t;

接口

的接口定義可以由類和結構來實現的合同。接口可以包含方法,屬性,事件和索引器。接口不提供它定義的成員的實現 - 它僅指定必須由實現接口的類或結構提供的成員。

接口可以采用多重繼承。在以下示例中,接口IComboBox繼承自ITextBox和IListBox。

1 interface IControl 2 { 3 void Paint(); 4 } 5 6 interface ITextBox: IControl 7 { 8 void SetText(string text); 9 } 10 11 interface IListBox: IControl 12 { 13 void SetItems(string[] items); 14 } 15 16 interface IComboBox: ITextBox, IListBox {}

類和結構可以實現多個接口。在以下示例中,該類EditBox實現了IControl和IDataBound。

1 interface IDataBound 2 { 3 void Bind(Binder b); 4 } 5 6 public class EditBox: IControl, IDataBound 7 { 8 public void Paint() {...} 9 public void Bind(Binder b) {...} 10 }

當類或結構實現特定接口時,該類或結構的實例可以隱式轉換為該接口類型。例如

1 EditBox editBox = new EditBox(); 2 IControl control = editBox; 3 IDataBound dataBound = editBox;

如果實例不是靜態地知道實現特定接口,則可以使用動態類型轉換。例如,以下語句使用動態類型轉換來獲取對象IControl和IDataBound接口實現。因為對象的實際類型是EditBox,所以強制轉換成功。

1 object obj = new EditBox(); 2 IControl control = (IControl)obj; 3 IDataBound dataBound = (IDataBound)obj;

在前面的EditBox類中,Paint從該方法IControl接口和Bind從所述方法IDataBound接口使用實現的public成員。C#還支持顯式接口成員實現,類或結構可以使用它來避免創建成員public。使用完全限定的接口成員名稱編寫顯式接口成員實現。例如,EditBox該類可以使用顯式接口成員實現來實現IControl.Paint和IDataBound.Bind方法,如下所示。

?

1 public class EditBox: IControl, IDataBound 2 { 3 void IControl.Paint() {...} 4 void IDataBound.Bind(Binder b) {...} 5 }

只能通過接口類型訪問顯式接口成員。例如,IControl.Paint前一個EditBox類提供的實現只能通過首先將EditBox引用轉換為IControl接口類型來調用。

1 EditBox editBox = new EditBox(); 2 editBox.Paint(); // Error, no such method 3 IControl control = editBox; 4 control.Paint(); // Ok

枚舉

一個枚舉類型是一個獨特的值類型與一組命名為常量。下面的示例聲明和使用名為枚舉類型Color與三個恒定值,Red,Green,和Blue。

1 using System; 2 3 enum Color 4 { 5 Red, 6 Green, 7 Blue 8 } 9 10 class Test 11 { 12 static void PrintColor(Color color) { 13 switch (color) { 14 case Color.Red: 15 Console.WriteLine("Red"); 16 break; 17 case Color.Green: 18 Console.WriteLine("Green"); 19 break; 20 case Color.Blue: 21 Console.WriteLine("Blue"); 22 break; 23 default: 24 Console.WriteLine("Unknown color"); 25 break; 26 } 27 } 28 29 static void Main() { 30 Color c = Color.Red; 31 PrintColor(c); 32 PrintColor(Color.Blue); 33 } 34 }

每個枚舉類型都有一個相應的整數類型,稱為枚舉類型的基礎類型。未明確聲明基礎類型的枚舉類型具有基礎類型int。枚舉類型的存儲格式和可能值的范圍由其基礎類型確定。枚舉類型可以采用的值集不受其枚舉成員的限制。特別是,枚舉的基礎類型的任何值都可以強制轉換為枚舉類型,并且是該枚舉類型的唯一有效值。

以下示例聲明了一個以Alignment底層類型為名稱的枚舉類型sbyte。

1 enum Alignment: sbyte 2 { 3 Left = -1, 4 Center = 0, 5 Right = 1 6 }

如前面的示例所示,枚舉成員聲明可以包含指定成員值的常量表達式。每個枚舉成員的常量值必須在枚舉的基礎類型的范圍內。當枚舉成員聲明未明確指定值時,該成員的值為零(如果它是枚舉類型中的第一個成員)或文本前面的枚舉成員的值加1。

枚舉值可以使用類型轉換轉換為整數值,反之亦然。例如

1 int i = (int)Color.Blue; // int i = 2; 2 Color c = (Color)2; // Color c = Color.Blue;

任何枚舉類型的默認值是轉換為枚舉類型的整數值零。在變量自動初始化為默認值的情況下,這是給予枚舉類型變量的值。為了使枚舉類型的默認值易于使用,文字0隱式轉換為任何枚舉類型。因此,允許以下內容。

Color c = 0;

委托

一個委托類型代表與特定參數列表和返回類型的方法的引用。委托使得可以將方法視為可以分配給變量并作為參數傳遞的實體。委托類似于在其他一些語言中找到的函數指針的概念,但與函數指針不同,委托是面向對象的,類型安全的。

以下示例聲明并使用名為的委托類型Function。

1 using System; 2 3 delegate double Function(double x); 4 5 class Multiplier 6 { 7 double factor; 8 9 public Multiplier(double factor) { 10 this.factor = factor; 11 } 12 13 public double Multiply(double x) { 14 return x * factor; 15 } 16 } 17 18 class Test 19 { 20 static double Square(double x) { 21 return x * x; 22 } 23 24 static double[] Apply(double[] a, Function f) { 25 double[] result = new double[a.Length]; 26 for (int i = 0; i < a.Length; i++) result[i] = f(a[i]); 27 return result; 28 } 29 30 static void Main() { 31 double[] a = {0.0, 0.5, 1.0}; 32 double[] squares = Apply(a, Square); 33 double[] sines = Apply(a, Math.Sin); 34 Multiplier m = new Multiplier(2.0); 35 double[] doubles = Apply(a, m.Multiply); 36 } 37 }

Function委托類型的實例可以引用任何接受double參數并返回double值的方法。該Apply方法將給定Function的元素應用于a?double[],返回a?double[]與結果。在該Main方法中,Apply用于將三種不同的函數應用于a?double[]。

委托可以引用靜態方法(例如Square或Math.Sin在前面的示例中)或實例方法(例如m.Multiply在前面的示例中)。引用實例方法的委托也引用特定對象,并且當通過委托調用實例方法時,該對象變為this調用。

代理也可以使用匿名函數創建,這些函數是動態創建的“內聯方法”。匿名函數可以查看周圍方法的局部變量。因此,無需使用Multiplier類,就可以更輕松地編寫上面的乘數示例:

double[] doubles = Apply(a, (double x) => x * 2.0);

委托的一個有趣且有用的屬性是它不知道或不關心它引用的方法的類;?重要的是引用的方法具有與委托相同的參數和返回類型。

屬性

C#程序中的類型,成員和其他實體支持控制其行為的某些方面的修飾符。例如,一種方法的可訪問性使用受控public,protected,internal,和private改性劑。C#概括了此功能,以便用戶定義的聲明性信息類型可以附加到程序實體并在運行時檢索。程序通過定義和使用屬性來指定此附加聲明性信息。

以下示例聲明了一個HelpAttribute可放置在程序實體上的屬性,以提供指向其相關文檔的鏈接。

1 using System; 2 3 public class HelpAttribute: Attribute 4 { 5 string url; 6 string topic; 7 8 public HelpAttribute(string url) { 9 this.url = url; 10 } 11 12 public string Url { 13 get { return url; } 14 } 15 16 public string Topic { 17 get { return topic; } 18 set { topic = value; } 19 } 20 }

所有屬性類都派生自System.Attribute.NET Framework提供的基類。可以通過在關聯聲明之前的方括號內提供其名稱以及任何參數來應用屬性。如果屬性的名稱結束Attribute,則在引用該屬性時可以省略該部分名稱。例如,HelpAttribute屬性可以如下使用。

1 [Help("http://msdn.microsoft.com/.../MyClass.htm")] 2 public class Widget 3 { 4 [Help("http://msdn.microsoft.com/.../MyClass.htm", Topic = "Display")] 5 public void Display(string text) {} 6 }

此示例將a附加HelpAttribute到Widget類,將另一個附加到類HelpAttribute中的Display方法。屬性類的公共構造函數控制將屬性附加到程序實體時必須提供的信息??梢酝ㄟ^引用屬性類的公共讀寫屬性(例如Topic先前對屬性的引用)來提供附加信息。

以下示例顯示如何使用反射在運行時檢索給定程序實體的屬性信息。

1 using System; 2 using System.Reflection; 3 4 class Test 5 { 6 static void ShowHelp(MemberInfo member) { 7 HelpAttribute a = Attribute.GetCustomAttribute(member, 8 typeof(HelpAttribute)) as HelpAttribute; 9 if (a == null) { 10 Console.WriteLine("No help for {0}", member); 11 } 12 else { 13 Console.WriteLine("Help for {0}:", member); 14 Console.WriteLine(" Url={0}, Topic={1}", a.Url, a.Topic); 15 } 16 } 17 18 static void Main() { 19 ShowHelp(typeof(Widget)); 20 ShowHelp(typeof(Widget).GetMethod("Display")); 21 } 22 }

當通過反射請求特定屬性時,將使用程序源中提供的信息調用屬性類的構造函數,并返回結果屬性實例。如果通過屬性提供了其他信息,則在返回屬性實例之前將這些屬性設置為給定值。

?

轉載于:https://www.cnblogs.com/strengthen/p/9715923.html

總結

以上是生活随笔為你收集整理的C#6.0语言规范(一) 介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。