久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

C#學習心得(五篇材料)

時間:2019-05-12 15:15:33下載本文作者:會員上傳
簡介:寫寫幫文庫小編為你整理了多篇相關的《C#學習心得》,但愿對你工作學習有幫助,當然你在寫寫幫文庫還可以找到更多《C#學習心得》。

第一篇:C#學習心得

C#速成

一、緒論

C#是這樣的一種語言,具有C++的特點,象Java一樣的編程風格, 并且象Basic一樣的快速開發模型。如果你已經知道了C++,本文會在不到一個小時的時間內讓你迅速掌握C#的語法。熟悉Java的括會更好,因為Java的程序結構、打包(Packages)和垃圾收集的概念有助于你更快的了解C#。因此在討論C#的構造時,我會假定你了解C++。

本文會討論C#語言的構造與特點,同時會采取簡潔的和你能理解的方式使用些代碼示例,我們會盡量讓你能稍微看看這些代碼就能理解這些概念。

注意:本文不是為C#高手(C# gurus)所寫.這是針對在C#學習上還是初學者的文章。下面是將要討論的C#問題的目錄: 程序結構 命名空間 數據類型 變量

運算符和表達式 枚舉

語句(Statements)

類(Classes)和結構(Structs)修飾符(Modifiers)屬性(Properties)接口(Interfaces)方法參數(Function Parameters)數組(Arrays)索引器(Indexers)裝箱及拆箱操作 委托(Delegates)繼承和多態

下面的內容將不會在被討論之列:

C++與C#誰更通用

諸如垃圾回收、線程以及文件處理等概念 數據的類型轉換 異常處理.NET庫

二、程序結構

這一點象C++,C#是一種對大小寫字母敏感的語言,分號“;”是語句間的分隔符。與C++不同的是,C#當中聲明代碼文件(頭文件)與實現代碼文件(cpp文件)不是獨立存在的,所有代碼(類聲明和類實現)都位于一個擴展名為cs的文件內。

讓我們瞧瞧C#當中的 Hello world 程序是怎樣的。using System;namespace MyNameSpace { class HelloWorld { static void Main(string[] args){ Console.WriteLine(“Hello World”);} } }

在C#當中的每樣東西都被封裝到一個類中,C#的類又被封裝到一個命名空間當中(就象一個文件夾中的文件)。類似于 C++,main方法是你的程序的入口點。C++的main函數調用名稱是“main”,而C#的main函數是以大寫字母M為起點的名稱是“Main”。

沒有必要把分號分隔符放在類語句塊或者結構定義語句塊后。這在C++當中被要求,但在C#當中卻不是。

三、命名空間

每一個類都被包裝進一個命名空間。命名空間的概念與C++的完全相同,但在C#當中使用命名空間的頻率較C++還高。你可以使用點限定符(dot qulifier)訪問一個類。在上面的hello world程序當中MyNameSpace就是一個命名空間。

現在思考這樣的一個問題,你想從某些別的類的命名空間當中來訪問HelloWorld這個類該如何操作。

這有一個例子:

using System;namespace AnotherNameSpace { class AnotherClass { public void Func(){ Console.WriteLine(“Hello World”);} } }

現在,從你的HelloWorld類里你能象這樣去訪問上面的這個AnotherNameSpace的命名空間: using System;using AnotherNameSpace;// you will add this using statement namespace MyNameSpace { class HelloWorld { static void Main(string[] args){ AnotherClass obj = new AnotherClass();obj.Func();} } }

在.NET庫當中,System是位于頂層的命名空間,別的命名空間都存在這個命名空間之下。默認狀態下,存在一個全局的命名空間,因此一個在命名空間外定義的類將直接在這個全局命名空間之下;因此,你能在沒有任何點限定符的情況下訪問這個類。

四、變量

除以下區別外,C#當中的變量幾乎與C++同:

與C++不同,C#變量被訪問之前必須被初始化;否則編譯時會報錯。因此,訪問一個未初始化變量是不可能的事。

C#中你不會訪問到一個不確定的指針。(譯者注:嚴格說起來C#已經把指針概念異化,限制更嚴格。所以有些資料上會說C#取消了指針概念)一個超出數組邊界的表達式是不可訪問的。

C#中沒有全局(整個Application)的變量或全局函數,全局方式的操作是通過靜態函數和靜態變量來實現的。

五、數據類型

所有C#數據類型都派生自基類Object。這里有兩類數據類型: 基本型/內置型 用戶自定義型 下面一個C#內置類型列表:

類型 字節數 解釋 byte 1 無符號字節型 sbyte 1 有符號字節型 short 2 有符號短字節型 ushort 2 無符號短字節型 int 4 有符號整型 uint 4 無符號整型 long 8 有符號長整型 ulong 8 無符號長整型 float 4 浮點數 double 8 雙精度數 decimal 8 固定精度數 string unicode字串型 char unicode字符型 bool 真假布爾型

注意:C#當中的類型范圍與C++有所不同;例如,C++的long型是4個字節,而在C#當中是8個字節。同樣地,bool型和string型都不同于C++。bool型只接受true和false兩種值。不接受任何整數類型。

用戶定義類型包括: 類類型(class)結構類型(struct)接口類型(interface)

數據類型的內存分配形式的不同又把它們分成了兩種類型: 值類型(Value Types)

引用類型(Reference Types)

值類型:

值類型數據在棧中分配。他們包括:所有基本或內置類型(不包括string類型)、結構類型、枚舉類型(enum type)

引用類型:

引用類型在堆中分配,當它們不再被使用時將被垃圾收集。它們使用new運算符來創建,對這些類型而言,不存在C++當中的delete操作符,根本不同于C++會顯式使用delete這個運算符去釋放創建的這個類型。C#中,通過垃圾收集器,這些類型會自動被收集處理。引用類型包括:類類型、接口類型、象數組這樣的集合類型類型、字串類型、枚舉類型 枚舉類型與C++當中的概念非常相似。它們都通過一個enum關鍵字來定義。示例:

enum Weekdays { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday }

類類型與結構類型的比較

除了在內存分配形式上外,類與結構的概念完全與C++相同。類的對象被分配在堆中,并且通過new來創建,結構也是被new創建但卻被分配在棧當中。C#當中,結構型適于快速訪問和擁有少量成員的數據類型。如果涉及量較多,你應該創建一個類來實現他。

(譯者注:這與堆和棧內存分配結構的特點有關。簡而言之,棧是一種順序分配的內存;堆是不一定是連續的內存空間。具體內容需要大家參閱相關資料)示例:

struct Date { int day;int month;int year;}

class Date { int day;int month;int year;string weekday;string monthName;

public int GetDay(){ return day;}

public int GetMonth(){ return month;}

public int GetYear(){ return year;}

public void SetDay(int Day){ day = Day;}

public void SetMonth(int Month){ month = Month;}

public void SetYear(int Year){ year = Year;}

public bool IsLeapYear(){ return(year/4 == 0);}

public void SetDate(int day, int month, int year){

}...}

六、屬性

如果你熟悉C++面象對象的方式,你就一定有一個屬性的概念。在上面示例當中,以C++的觀點來看,Data類的屬性就是day、month和year。用C#方式,你可以把它們寫成Get和Set方法。C#提供了一個更方便、簡單、直接的方式來訪問屬性。

因此上面的類可以被寫成:

using System;class Date { int day;public int Day{ get { return day;}

set { day = value;} }

int month;

public int Month{

get { return month;}

set { month = value;} }

int year;

public int Year{

get { return year;}

set { year = value;} }

public bool IsLeapYear(int year){ return year%4== 0 ? true: false;}

public void SetDate(int day, int month, int year){ this.day = day;this.month = month;this.year = year;} }

你可在這里得到并設置這些屬性:

class User {

public static void Main(){ Date date = new Date();date.Day = 27;date.Month = 6;date.Year = 2003;Console.WriteLine(“Date: {0}/{1}/{2}”, date.Day, date.Month, date.Year);} }

七、修飾符

你必須已經知道public、private、protected這些常在C++當中使用的修飾符。這里我會討論一些C#引入的新的修飾符。readonly(只讀)

readonly修飾符僅在類的數據成員中使用。正如這名字所提示的,readonly 數據成員僅能只讀,它們只能在構造函數或是直接初始化操作下賦值一次。readonly與const數據成員不同,const 要求你在聲明中初始化,這是直接進行的??聪旅娴氖纠a: class MyClass {

const int constInt = 100;//直接初始化

readonly int myInt = 5;//直接初始化

readonly int myInt2;//譯者注:僅做聲明,未做初始化

public MyClass(){ myInt2 = 8;//間接的 }

public Func(){ myInt = 7;//非法操作(譯者注:不得賦值兩次)Console.WriteLine(myInt2.ToString());} }

sealed(密封)

密封類不允許任何類繼承,它沒有派生類。因此,你可以對你不想被繼承的類使用sealed關鍵字。

sealed class CanNotbeTheParent { int a = 5;}

unsafe(不安全)

你可使用unsafe修飾符來定義一個不安全的上下文。在不安全的上下文里,你能寫些如C++指針這樣的不安全的代碼。看下面的示例代碼:

public unsafe MyFunction(int * pInt, double* pDouble){ int* pAnotherInt = new int;*pAnotherInt = 10;pInt = pAnotherInt;...*pDouble = 8.9;}

八、interface(接口)

如果你有COM方面的概念,你會立亥明白我要談論的內容。一個接口就是一個抽象的基類,這個基類僅僅包含功能描述,而這些功能的實現則由子類來完成。C#中你要用interface關鍵字來定義象接口這樣的類。.NET就是基于這樣的接口上的。C#中你不支持C++所允許的類多繼承(譯者注:即一個派生類可以從兩個或兩個以上的父類中派生)。但是多繼承方式可以通過接口獲得。也就是說你的一個子類可以從多個接口中派生實現。interface myDrawing { int originx { get;set;} int originy { get;set;} void Draw(object shape);} class Shape: myDrawing { int OriX;int OriY;public int originx { get{ return OriX;} set{ OriX = value;} } public int originy { get{ return OriY;} set{ OriY = value;} } public void Draw(object shape){...// do something }

// class's own method public void MoveShape(int newX, int newY){.....} }

九、Arrays(數組)

C#中的數組比C++的表現更好。數組被分配在堆中,因此是引用類型。你不可能訪問超出一個數組邊界的元素。因此,C#會防止這樣類型的bug。一些輔助方式可以循環依次訪問數組元素的功能也被提供了,foreach就是這樣的一個語句。與C++相比,C#在數組語法上的特點如下: 方括號被置于數據類型之后而不是在變量名之后。創建數組元素要使用new操作符。

C#支持一維、多維以及交錯數組(數組中的數組)。示例:

int[] array = new int[10];// 整型一維數組 for(int i = 0;i < array.Length;i++){ array[i] = i;} int[,] array2 = new int[5,10];// 整型二維數組 array2[1,2] = 5;int[,] array3 = new int[5,10,5];// 整型的三維數組 array3[0,2,4] = 9;int[][] arrayOfarray = = new int[2];// 整型交錯數組(數組中的數組)arrayOfarray[0] = new int[4];arrayOfarray[0] = new int[] {1,2,15};

十、索引器

索引器被用于寫一個訪問集合元素的方法,集合使用“[]”這樣的直接方式,類似于數組。你所要做的就是列出訪問實例或元素的索引清單。類的屬性帶的是輸入參數,而索引器帶的是元素的索引表,除此而外,他們二者的語法相同。示例: 注意:CollectionBase是一個制作集合的庫類。List是一個protected型的CollectionBase成員,儲存著集合清單列表。class Shapes: CollectionBase { public void add(Shape shp){ List.Add(shp);} //indexer public Shape this[int index] { get { return(Shape)List[index];} set { List[index] = value;} } }

十一、裝箱和拆箱操作(Boxing/Unboxing)

C#的裝箱思想是全新的。上面提到過所有的數據類型,不論內置或用戶自定義,全都從命名空間System的一個基類object派生出來。因此把基本的或者原始類型轉換成object類型被稱做裝箱,反之,這種方式的逆操作被稱為拆箱。示例: class Test { static void Main(){ int myInt = 12;object obj = myInt;// 裝箱 int myInt2 =(int)obj;// 拆箱 } }

示例展示了裝箱和拆箱操作。一個整型值轉換成object類型,然后又轉換回整型。當一個值類型的變量需要轉換成引用類型時,一個object的箱子會被分配容納這個值的空間,這個值會被復制進這個箱子。拆箱與此相反,一個object箱子中的數據被轉換成它的原始值類型時,這個值將被從箱中復制到適當的存儲位置。

十二、方法參數

C#中有三種類型的參數:

值參數/輸入型參數

引用型參數/輸入輸出型參數 Out參數

如果你有COM接口和它的參數類型的概念,你會很容易理解C#參數類型。值參數/輸入型參數

值概念與C++相同。所要傳遞的值會被復制到一個位置上并被傳遞給函數。示例: SetDay(5);void SetDay(int day){....}

引用型參數/輸入輸出參數

C#中的引用參數既不是C++中的指針也不是引用操作符(&)來傳遞的。C#的引用型參數減少了出錯的可能。引用型參數也被稱作輸入輸出參數,因為你傳遞了一個引用地址,因此你可以從函數中傳遞一個輸入值并且可以獲得一個輸出值。

你不能把一個未經初始化的引用型參數傳遞給函數。C#用ref這個關鍵字來聲明引用型參數。當你傳遞一個變量給函數要求的引用參數時必須使用一個ref關鍵字說明。示例:

int a= 5;FunctionA(ref a);// 要用ref聲明變量,否則你會得到 // 一個編譯錯誤

Console.WriteLine(a);// 指向地址的值為20 void FunctionA(ref int Val){ int x= Val;Val = x* 4;}

Out參數

Out型參數僅僅從函數當中返回一個值。不要求有輸入值。C#用關鍵字out來描聲明這個參數 示例:

int Val;GetNodeValue(Val);bool GetNodeValue(out int Val){ Val = value;return true;}

可變數量的參數和數組

數組在C#當中是通過關鍵字params來描述傳遞的。作為數組類型的變量,你能傳遞任意數量的元素。從下面示例中你可以理解的更好。示例:

void Func(params int[] array){ Console.WriteLine(“number of elements {0}”,array.Length);} Func();// prints 0 Func(5);// prints 1 Func(7,9);// prints 2 Func(new int[] {3,8,10});// prints 3 int[] array = new int[8] {1,3,4,5,5,6,7,5};Func(array);// prints 8

十三、運算符和表達式

運算符和表達式概念與C++完全相同。但是一些新的有用的運算符被填加了進來。我將在這里討論其中的某些部分。

is 運算符

is 運算符被用于檢查操作數的類型是否相同或者是否可以轉換。is 運算符在多態環境下特別有用。它有兩個操作數,運算結果是一個布爾型??催@個示例: void function(object param){ if(param is ClassA)//do something else if(param is MyStruct)//do something } } as 運算符

as 運算符檢查操作數的類型是否可被轉換或者是否相等(這些 as通過 is 運算符來完成。如果結果是可轉換的,則結果將被轉換或者被裝箱,成object(關于as運算符進行裝箱成目標類型的操作請看前面的裝箱/拆箱操作)。如果不可轉換或者裝箱,則返回值是null。瞧一瞧下面的例子我們會更好地理解這個概念。Shape shp = new Shape();Vehicle veh = shp as Vehicle;// 結果是null, 類型不可轉換 Circle cir = new Circle();Shape shp = cir;Circle cir2 = shp as Circle;//會被轉換 object[] objects = new object[2];objects[0] = “Aisha”;object[1] = new Shape();string str;for(int i=0;i&< objects.Length;i++){ str = objects[i] as string;if(str == null)Console.WriteLine(“can not be converted”);else Console.WriteLine(“{0}”,str);} 輸出: Aisha can not be converted

十四、語句

除了對某些新增語句和對某些語句的修改以外,C#語句與C++非常相象。下面是新增的語句: foreach 用于循環依次訪問集合元素,比如象數組等。示例: foreach(string s in array)Console.WriteLine(s);lock 用于鎖住代碼塊,使線程在臨界爭區內,別的線程無法進入鎖定的臨界區。

checked/unchecked 用于數值運算中的溢出檢測。示例:

int x = Int32.MaxValue;x++;// 溢出檢測 { x++;// 異常

}

unchecked { x++;// 溢出} }

下面的語句在C#當中已經被修改: Switch 執行一個case語句后,程序流程不允許跳到下一個相鄰case語句。這在C++當中是被允許的。示例:

int var = 100;switch(var){ case 100: Console.WriteLine(“”);// 沒有break語句

case 200: Console.WriteLine(“”);break;}

C++編譯后的輸出:

C#下,編譯時會報錯:

error CS0163: Control cannot fall through from one case label('case 100:')to another 但是你仍然能做C++類似的事 switch(var){ case 100: case 200: Console.WriteLine(“100 or 200”);break;}

你也可以常數變量作為case 的值: 示例:

const string WeekEnd = “Sunday”;const string WeekDay1 = “Monday”;....string WeekDay = Console.ReadLine();switch(WeekDay){ case WeekEnd: Console.WriteLine(“It's weekend!”);break;case WeekDay1: Console.WriteLine(“It's Monday”);break;}

十五、委托

委托讓我們把一個函數引用存儲在一個變量里。C++當中,這類似于使用typedef定義的函數指針,我們通常用存儲一個函數指針。

聲明委托使用的關鍵字是 delegate。瞧瞧這個示例,你會理解什么是委托: 示例:

delegate int Operation(int val1, int val2);public int Add(int val1, int val2){ return val1 + val2;}

public int Subtract(int val1, int val2){ return val1-val2;}

public void Perform(){ Operation Oper;Console.WriteLine(“Enter + or-”);string optor = Console.ReadLine();Console.WriteLine(“Enter 2 operands”);string opnd1 = Console.ReadLine();string opnd2 = Console.ReadLine();int val1 = Convert.ToInt32(opnd1);int val2 = Convert.ToInt32(opnd2);if(optor == “+”)Oper = new Operation(Add);Else Oper = new Operation(Subtract);Console.WriteLine(“ Result = {0}”, Oper(val1, val2));}

十六、繼承和多態

C#僅允許單繼承,多繼承要通過接口來實現。示例:

class Parent { } class Child : Parent { }

十七、虛擬方法

除了在子類中實現虛擬方法采用override關鍵字外,虛擬方法實現多態的概念C#與C++相同。父類使用相同的virtual關鍵字。從重載虛擬方法的每個類都要使用override關鍵字。class Shape { public virtual void Draw(){ Console.WriteLine(“Shape.Draw”);} }

class Rectangle : Shape { public override void Draw(){ Console.WriteLine(“Rectangle.Draw”);} }

class Square : Rectangle { public override void Draw(){ Console.WriteLine(“Square.Draw”);} }

class MainClass { static void Main(string[] args){ Shape[] shp = new Shape[3];Rectangle rect = new Rectangle();shp[0] = new Shape();shp[1] = rect;shp[2] = new Square();shp[0].Draw();shp[1].Draw();shp[2].Draw();} }

輸出t: Shape.Draw Rectangle.Draw Square.Draw

十八、使用“new”來隱藏父方法

你可以定義一個子類成一個新方法版本,隱藏基類當中的那個版本。使用new關鍵字就可以定義一個新版本。思考下面的示例,它是上面示例的修改后的版本。注意當我用Rectangle類中的new關鍵字代替override關鍵字時示例的輸出情況。

class Shape { public virtual void Draw(){ Console.WriteLine(“Shape.Draw”);} }

class Rectangle : Shape { public new void Draw(){ Console.WriteLine(“Rectangle.Draw”);} } class Square : Rectangle { //沒在這里讓你重載 public new void Draw(){ Console.WriteLine(“Square.Draw”);} } class MainClass { static void Main(string[] args){ Console.WriteLine(“Using Polymorphism:”);Shape[] shp = new Shape[3];Rectangle rect = new Rectangle();shp[0] = new Shape();shp[1] = rect;shp[2] = new Square();shp[0].Draw();shp[1].Draw();shp[2].Draw();Console.WriteLine(“Using without Polymorphism:”);rect.Draw();Square sqr = new Square();sqr.Draw();} } 輸出: Using Polymorphism Shape.Draw Shape.Draw Shape.Draw Using without Polymorphism: Rectangle.Draw Square.Draw 這里的多態性不會把Rectangle類的Draw方法當做Shape的Draw方法多態性的一種表現。相反,它會認為這是一種不同的方法。因此,為了避免父類與子類間的命名沖突,我們使用了new修飾符。注意:你不能使用同一類下面一種方法的兩個版本,即一個是用new修飾符的版本,另一個是用override或virtual修飾符的版本。正象上面示例所說明的,我不能再在擁有virtual或override方法的Rectangle類中添加另一個命名為Draw的方法。同樣地,在Square類中,我也不能重載Square類的虛擬的Draw方法。

十九、調用基類成員

如果子類與基類有同名的數據成員,為避免命名沖突,訪問基類數據成員和函要使用一個關鍵字base。在下面的示例中我們來看看如何調用基類的構造函數以及如何使用數據成員。public Child(int val):base(val){ myVar = 5;base.myVar;}

或者

public Child(int val){ base(val);myVar = 5;base.myVar;}

文學の音聲図書館[轉貼]

みなさん: こんにちは。私がつくった「文學の音聲図書館」をご覧下さい。みなさまの聴力に役立つかもしれません。どうぞ。

http://作家辭典http://horagai.com/歌舞伎文庫http://http://日語教材 http://seki.nease.net/yufa.htm 語法網站======================================外來語從此不再可怕http://[align=right][color=#000066][此貼子已經被作者于2005-1-27 20:18:53編輯過][/color][/align]

第二篇:C#學習心得

集合聲明:類B可以換成任意object對象

1、CollectionBase

類A繼承CollectionBase類,通過CollectionBase的成員List實現類A的Add(類

B)、Remove(類B)和RemoveAt(類B)方法:

publicvoidAdd(類B newB)

{List.Add(newB);}

publicvoidRemove(類B newB)

{List.Remove(newB);}

publicvoidRemoveAt(int index)

{List.RemoveAt(index);}

在類A中建立索引可以按類似數組的方法訪問。

public 類B this[int index]

{get{return(類B)List[index];}

set{List[index]=value;}

}

利用CollectionBase的成員InnerList(ArrayList對象)實現類A的Contains()方法:

publicboolContains(類B newB)

{

returnInnerList.Contains(newB);

}

注意:InnerList是ArrayList類實例,其Contains方法通過調用Object.Equals確定相等性,Equals默認實現僅支持引用相等。對于引用類型,相等定義為對象相等,即這些引用是否引用同一對象。對于值類型,相等定義為按位相等。

可以在類B中重寫Object.Equals方法和GetHashCode()方法。publicoverrideboolEquals(objectobj)

{//Check for null and compare run-time types.if(obj == null || GetType()!= obj.GetType())returnfalse;

B b =(B)obj;

return(比較邏輯);

}

publicoverrideintGetHashCode(){??}

2、DictionaryBase

類A繼承DictionaryBase類,通過DictionaryBase的成員

Dictionary(IDictionary類型的接口),實現類A的 Add(object key,類B)和Remove(object key,類B)方法:

publicvoidAdd(object key,類B newB)

{Dictionary.Add(key,newB);}

publicvoidRemove(object key,類B newB)

{Dictionary.Remove(key,newB);}

在類A中建立索引可以按類似數組的方法訪問。

public 類B this[object index]

{get{return(類B)Dictionary[index];}

set{Dictionary[index]=value;}

}

利用DictionaryBase的接口成員Dictionary實現類A的Contains()方法: publicboolContains(object key)

{

returnDictionary.Contains(key);

}

3、迭代器

對于繼承CollectionBase類的A,使用

foreach(BsourceBin類A對象){}

對于繼承DictionaryBase類的A,使用

foreach(DictionaryEntrysourceBin類A對象){source.Value.}

對于類迭代,使用方法GetEnumerator(),返回類型是IEnumerator;類成員迭代使用IEnumerable(),返回類型是IEnumerable;

例如繼承DictionaryBase類的A的迭代器,public new IEnumeratorGetEnumerator()

{foreach(object b in Dictionary.Values)

yield return(B)b;

}

以后使用foreach循環時,可按照類似繼承CollectionBase類的的方式使用。

4、淺度復制與深度復制

淺度復制:簡單地按照成員復制對象可以通過派生于System.Object的MemberwiseClone()方法來完成,這是一個受保護的方法,但是很容易在對象上定義一個調用該方法的公共方法例如GetCopy()。這個方法的復制功能成為淺復制。淺拷貝是對引用類型拷貝地址,對值類型直接進行拷貝,但是string類例外,因為string是readonly的,當改變string類型的數據值時,將重新分配了內存地址。數組、類也是淺度復制,而結構體、數值型、枚舉是深度復制。

深度復制:需要深度復制的類A添加ICloneable接口,實現該接口的Clone()方法。

public object Clone()

{A newA=new A();

object []arr=new object[維度];//object 可以是數值類型,string //不能使用newA.arr=arr;因為通過數組名賦值引用同一地址,是淺度復制 arr.CopyTo(newA.arr,0);

returnnewA;}

假設類A中有成員對象類B實例myB,則在類B定義中也要實現ICloneable的Clone()方法,class B:ICloneable

{

public object Clone(){??}

}

然后在類A的Clone方法中,newA.myB=myB.Clone();

比較

1、is運算符

檢查對象是否是給定類型或者是否可以轉換為給定類型,是則返回true。 is

如果type是類類型,operand也是該類型,或繼承該類型、封箱到該類型,為true 如果type是接口類型,operand也是該類型,或實現該接口的類型,為true 如果type是值類型,operand也是該類型,或拆箱到該類型,為true2、運算符重載

public static 返回類型 operator 需重載的運算符(參數??){}

注意不能重載賦值運算符,&&和||運算符,但可重載&和|;有些運算符需成對重載,如“<”和“>”

3、IComparable接口

類A實現IComparable接口的方法intCompareTo(objectobj)后,利用成員為類A的實例的ArrayList或Array類可以調用Sort()方法,按CompareTo(objectobj)的方法排序。

4、IComparer接口

類A實現IComparer接口的方法intCompare(objectx, objecty)后,利用ArrayList或Array類可以調用Sort(IA)方法(IComparer IA=new A()),按

Compare(,)方法排序。注意ArrayList或Array類的實例不一定是類A。也可以在類A中定義一個公用動態接口成員IComparer ID,這樣可以直接調用Sort(ID)。另外,在Compare方法中可以調用Comparer.Default.Compare(,)方法,實現特定的關鍵字排序。Default是Compare類的動態實例。

轉換

1、隱式和顯示轉換

在沒有繼承關系,沒有共享接口的類型之間轉換時,必須定義類型之間的隱式和顯示轉換。public classA

{??

//定義A到B的隱式轉換

public staticimplicit operatorzhuanB(Aa){?? return }

}

public classB

{??

//定義B到A的顯式轉換

public staticexplicit operatorzhuanA(Bb){??return }

}

2、as運算符

把類型轉換為給定類型。

is

operand類型是type類型,或可以隱式轉換為type類型,或封箱到type類型 如果不能轉換,則表達式的結果是null

異常處理

Exception:所有異常對象的基類。

SystemException:運行時產生的所有錯誤的基類。

IndexOutOfRangeException:當一個數組的下標超出范圍時運行時引發。NullReferenceException:當一個空對象被引用時運行時引發。

InvalidOperationException:當對方法的調用對對象的當前狀態無效時,由某些方法引發。

ArgumentException:所有參數異常的基類。

ArgumentNullException:在參數為空(不允許)的情況下,由方法引發。ArgumentOutOfRangeException:當參數不在一個給定范圍之內時,由方法引發。

InteropException:目標在或發生在CLR外面環境中的異常的基類。ComException:包含COM類的HRESULT信息的異常。

SEHException:封裝Win32結構異常處理信息的異常。

SqlException:封裝了SQL操作異常。

常見具體的異常對象:

ArgumentNullException一個空參數傳遞給方法,該方法不能接受該參數ArgumentOutOfRangeException參數值超出范圍

ArithmeticException出現算術上溢或者下溢

ArrayTypeMismatchException試圖在數組中存儲錯誤類型的對象

BadImageFormatException圖形的格式錯誤

DivideByZeroException除零異常

DllNotFoundException找不到引用的DLL

FormatException參數格式錯誤

IndexOutOfRangeException數組索引超出范圍

InvalidCastException使用無效的類

InvalidOperationException方法的調用時間錯誤

NotSupportedException調用的方法在類中沒有實現

NullReferenceException試圖使用一個未分配的引用OutOfMemoryException內存空間不夠

StackOverflowException堆棧溢出

第三篇:C#面向對象學習心得

一、封裝

這是一種隱藏信息的特性。拿本節引例來說,類CalculateDate 將數據結構與算法隱藏在類的內部,外界使用者無需知道具體技術實現細節即可使用此類。封裝這一特性不僅大大提高了代碼的易用性,而且還使得類的開發者可以方便地更換新的算法,這種變化不會影響使用類的外部代碼??梢杂靡韵鹿秸故绢惖姆庋b特性:封裝的類=數據+對此數據所進行的操作(即算法)。通俗地說,封裝就是:包起外界不必需要知道的東西,只向外界展露可供展示的東西。在面向對象理論中,封裝這個概念擁有更為寬廣的含義。小到一個簡單的數據結構,大到一個完整的軟件子系統,靜態的如某軟件系統要收集數據信息項,動態的如某個工作處理流程,都可以封裝到一個類中。具備這種“封裝”的意識,是掌握面向對象分析與設計技巧的關鍵。

二、繼承

繼承是面向對象編程中一個非常重要的特性,它也是另一個重要特性——多態的基礎?,F實生活中的事物都歸屬于一定的類別。在一些書中,將父類稱為超類(super class)。“繼承”關系有時又稱為“派生”關系,“B 繼承自A”,可以說為“B 派生自A”,或反過來說,“A 派生出B”。父類與子類之間擁有以下兩個基本特性:

(1)是一種(IS-A)關系:子類是父類的一種特例。

(2)擴充(Extends)關系:子類擁有父類所沒有的功能。

1.類成員的訪問權限

面向對象編程的一大特點就是可以控制類成員的可訪問性。當前主流的面向對象語言都擁有以下三種基本的可訪問性:

(1)公有 public 訪問不受限制。

(2)私有 private 只有類自身成員可以訪問。

(3)保護 protected 子類可以訪問,其他類無法訪問。

由此可見,可以通過子類對象訪問其父類的所有公有成員,事實上,外界根本分不清楚對象的哪些公有成員來自父類,哪些公有成員來自子類自身。小結一下繼承條件下的類成員訪問權限:

(1)所有不必讓外人知道的東西都是私有的。

(2)所有需要向外提供的服務都是公有的。

(3)所有的“祖傳絕招”,“秘不外傳”的都是保護的。

C#中還有一種可訪問性,就是由關鍵字internal 所確定的“內部”訪問性。internal 有點像public,外界類也可以直接訪問聲明為internal 的類或類的成員,但這只局限于同一個程序集內部。

讀者可以簡單地將程序集理解為一個獨立的DLL 或EXE 文件。一個DLL 或EXE 文件中可以有多個類,如果某個類可被同一程序集中的類訪問,但其他程序集中的類不能訪問它,則稱此類具有internal 訪問性。internal 是C#的默認可訪問性,這就是說,如果某個類沒有任何可訪問性關鍵字在它前面,則它就是internal 的。

2.子類父類變量的相互賦值

子類對象可以被當成基類對象使用。這是因為子類對象本就是一種(IS_A)父類對象,因此,以下代碼是合法的:

Parent p;

Son c = new Son();

p = c;

然而,反過來就不可以,父類對象變量不可以直接賦值給子類變量。如果確信父類變量中所引用的對象的確是子類類型,則可以通過類型強制轉換進行賦值,其語法格式為: 子類對象變量=(子類名稱)基類對象變量;

子類對象變量=基類對象變量 as 子類名稱;

3.方法重載、隱藏與虛方法調用

由于子類對象同時匯集了父類和子類的所有公共方法,而C#并未對子類和父類的方法名稱進行過多限制,因此,一個問題出現了:如果子類中某個方法與父類方法的簽名一樣(即方法名和方法參數都一樣),那當通過子類對象訪問此方法時,訪問的是子類還是父類所定義的方法?讓我們先從子類方法與父類方法之間的關系說起??偟膩碚f,子類方法與父類方法之間的關系可以概括為以下三種:

(1)擴充(Extend):子類方法,父類沒有;

(2)重載(Overload):子類有父類的同名函數,但參數類型或數目不一樣;

(3)完全相同:子類方法與父類方法從方法名稱到參數類型完全一樣。

當子類與父類擁有完全一樣的方法時,稱“子類隱藏了父類的同名方法,當分別位于父類和子類的兩個方法完全一樣時,調用哪個方法由對象變量的類型決定?!皀ew”關鍵字明確告訴C#編譯器,子類隱藏父類的同名方法,提供自己的新版本。如果子類隱藏了父類的同名方法,要在子類方法的實現代碼中調用父類被隱藏的同名方法時要使用base 關鍵字。如果子類隱藏了父類的同名方法,不進行強制轉換,就無法通過父類變量直接調用子類的同名方法,哪怕父類變量引用的是子類對象。這是不太合理的。我們希望每個對象都只干自己職責之內的事,即如果父類變量引用的是子類對象,則調用的就是子類定義的方法,而如果父類變量引用的就是父類對象,則調用的是父類定義的方法。這就是說,希望每個對象都“各人自掃門前雪,莫管他人瓦上霜”。為達到這個目的,可以在父類同名方法前加關鍵字virtual,表明這是一個虛方法,子類可以重寫此方法:即在子類同名方法前加關鍵字override,表明對父類同名方法進行了重寫。所以,將父類方法定義為虛方法,子類重寫同名方法之后,通過父類變量調用此方法,到底是調用父類還是子類的,由父類變量引用的真實對象類型決定,而與父類變量無關!很明顯,“虛方法調用”特性可以讓我們寫出非常靈活的代碼,大大減少由于系統功能

擴充和改變所帶來的大量代碼修改工作量。由此給出結論:面向對象語言擁有的“虛方法調用”特性,使我們可以只用同樣的一個語句,在運行時根據對象類型而執行不同的操作。

三、抽象

1.抽象類與抽象方法

在一個類前面加上“abstract”關鍵字,此類就成為了抽象類。對應地,一個方法類前面加上“abstract”關鍵字,此方法就成為了抽象方法。注意抽象方法不能有實現代碼,在函數名后直接跟一個分號。抽象類專用于派生出子類,子類必須實現抽象類所聲明的抽象方法,否則,子類仍是抽象類。抽象類一般用于表達一種比較抽象的事物,而抽象方法則說明此抽象類應該具有的某種性質,從同一抽象類中繼承的子類擁有相同的方法(即抽象類所定義的抽象方法),但這些方法的具體代碼每個類都可以不一樣。抽象類不能創建對象,一般用

它來引用子類對象。一個抽象類中可以包含非抽象的方法和字段。因此:包含抽象方法的類一定是抽象類,但抽象類中的方法不一定是抽象方法。除了方法可以是抽象的之外,屬性也可以是抽象的。

2.接口

接口可以看成是一種“純”的抽象類,它的所有方法都是抽象方法。抽象類定義了對象所屬的類別,而接口實際上定義了一種對象應具有的行為特性。某個類可以實現多個接口,當創建一個此類的對象之后,通過引用這個對象的對象變量可以訪問其所有的公有方法(包括自身的公有方法以及由接口定義的公有方法以)。在這種情況下,根本分不清哪些方法是由接口定義的,哪些是由類自己定義的。C#提供了一種“顯式接口”實現機制,可以區分開這兩種情況。由此得到一個結論:如果一個類顯式實現某個接口,則只能以此接口類型的變量為媒介調用此接口所定義的方法,而不允許通過類的對象變量直接調用?;蛘哌@樣說:被顯式實現的接口方法只能通過接口實例訪問,而不能通過類實例直接訪問。

四、多態

方法重載屬于多態的一種,兩個構成重載關系的函數必須滿足幾個條件:函數名相同、參數類型不同,或參數個數不同。具體調用哪個方法要看參數,需要注意的是,方法返回值類型的不同不是方法重載的判斷條件。多態編程的基本原理是:使用基類或接口變量編程。在多態編程中,基類一般都是抽象基類,其中擁有一個或多個抽象方法,各個子類可以根據需要重寫這些方法?;蛘呤褂媒涌冢總€接口都規定了一個或多個抽象方法,實現接口的類根據需要實現這些方法。因此,多態的實現分為兩大基本類別:繼承多態和接口多態。

1.接口多態與繼承多態

接口多態與繼承多態其編程方式與作用都是類似的。但由于一個類可以實現多個接口,所以,接口多態較繼承多態更靈活,因而在編程中也用得更廣。多態是面向對象技術中最精華的部分之一。大量的精巧軟件設計方案都建立在對多態特性的巧妙應用上。在編程中應用多態,可以將其簡化為兩句:應用繼承實現對象的統一管理;應用接口定義對象的行為特性。對比傳統的不使用多態的編程方式,使用多態的好處是:當要修改程序并擴充系統時,需要修改的地方較少,對其他部分代碼的影響較小。

五、類與對象

類是面向對象編程的基本單元,與使用C語言等結構化編程語言不一樣,使用C#編程,所有的程序代碼幾乎都放在類中,不存在獨立于類之外的函數。一個類可以包含兩種成員:靜態成員和實例成員,靜態成員是供類的所有對象所共享的,而實例成員只供某一個對象所有。實例成員與靜態成員的訪問規則:位于同一類中的實例方法可直接相互調用;類的字段(包括實例字段和靜態字段)可以被同一類中的所有實例方法直接訪問;類中的靜態方法只能直接訪問類靜態字段。

類中包括:方法和字段,屬性是一種特殊的字段,它可以保證數據的合法性,方法和字段這兩個概念是面向對象理論的術語,是通用于各種面向對象語言的。字段(Field)代表了類中的數據,在類的所有方法之外定義一個變量即定義了一個字段。在變量之前可以加上public、private 和protected 表示字段的訪問權限。方法(function)功能代碼的集合,在程序開發過程中,經常發現多處需要實現或調用某一個公用功能,這些功能的實現都需要書

寫若干行代碼。如果在調用此功能的地方重復書寫這些功能代碼,將會使整個程序中代碼大量重復,會增大開發工作量,增加代碼維護的難度。為了解決代碼重復的問題,絕大多數程序設計語言都將完成某一公用功能的多個語句組合在一起,起一個名字用于代表這些語句的全體,這樣的代碼塊被稱為“函數(function)”。引入“函數”概念之后,程序中凡需要調用此公用功能的地方都可以只寫出函數名,此名字就代表了函數中所包含的所有代碼,這樣一來,就不再需要在多個地方重復書寫這些功能代碼。

對象是以類為模板創建出來的。類與對象之間是一對多的關系。在C#中,使用new 關鍵字創建對象。在程序中“活躍”的是對象而不是類。在面向對象領域,對象有時又被稱為是“類的實例”,“對象”與“類的實例”這兩個概念是等同的。

六、值類型與引用類型

1.值類型

值類型變量與引用類型變量的內存分配模型也不一樣。每個正在運行的程序都對應著一個進程(process),在一個進程內部,可以有一個或多個線程(thread),每個線程都擁有一塊“自留地”,稱為“線程堆棧”,大小為1M,用于保存自身的一些數據,比如函數中定義的局部變量、函數調用時傳送的參數值等,這部分內存區域的分配與回收不需要程序員干涉。所有值類型的變量都是在線程堆棧中分配的。值類型共有三種:簡單類型、枚舉類型和結構類型。

2.引用類型

另一塊內存區域稱為“堆(heap)”,在.NET 這種托管環境下,堆由CLR 進行管理,所以又稱為“托管堆(managed heap)”。用new 關鍵字創建的類的對象時,分配給對象的內存單元就位于托管堆中。在程序中我們可以隨意地使用new 關鍵字創建多個對象,因此,托管堆中的內存資源是可以動態申請并使用的,當然用完了必須歸還。打個比方更易理解:托管堆相當于一個旅館,其中的房間相當于托管堆中所擁有的內存單元。當程序員用new 方法創建對象時,相當于游客向旅館預訂房間,旅館管理員會先看一下有沒有合適的空房間,有的話,就可以將此房間提供給游客住宿。當游客旅途結束,要辦理退房手續,房間又可以為其他旅客提供服務了。引用類型共有四種:類類型、接口類型、數組類型和委托類型。所有引用類型變量所引用的對象,其內存都是在托管堆中分配的。嚴格地說,我們常說的“對象變量”其實是類類型的引用變量。但在實際中人們經常將引用類型的變量簡稱為“對象變量”,用它來指代所有四種類型的引用變量。

七、命名空間與類庫

1.命名空間

在使用面向對象技術開發的現代軟件系統中,經常擁有數百甚至上千個類,為了方便地管理這些類,面向對象技術引入了“命名空間(namespace)”的概念。命名空間可以看成是類的“容器”,它可以包含多個類。.NET Framework 使用命名空間來管理所有的類。如果把類比喻成書的話,則命名空間類似于放書的書架,書放在書架上,類放在命名空間里。當我們去圖書館查找一本書時,需要指定這本書的編號,編號往往規定了書放在哪個書庫的哪個書架上,通過逐漸縮小的范圍:圖書館->書庫->書架,最終可以在某個書架中找到這本書。類似地,可以采用圖書館保存圖書類似的方法來管理類,通過逐漸縮小的范圍:最大的命名空間->子命名空間->孫命名空間??,最終找到一個類。

2.類庫

為了提高軟件開發的效率,人們在整個軟件開發過程中大量應用了軟件工程的模塊化原則,將可以在多個項目中使用的代碼封裝為可重用的軟件模塊,其于這些可復用的軟件模塊,再開發新項目就成為“重用已有模塊,再開發部分新模塊,最后將新舊模塊組裝起來”的過程。整個軟件開發過程類似于現代工業的生產流水線,生產線上的每個環節都由特定的人員負責,整個生產線上的工作人員既分工明確又相互合作,大大地提高了生產效率。在組件化開發大行其道的今天,人們通常將可以重用的軟件模塊稱為“軟件組件”。在全面向對象的.NET 軟件平臺之上,軟件組件的表現形式為程序集(Assembly),可以通過在Visual Studio 中創建并編譯一個類庫項目得到一個程序集。在Visual Studio 的項目模板中,可以很方便地創建類庫(Class Library)項目,Visual Studio 會自動在項目中添加一個名為Class1.cs 的類文件,程序員可在此類文件中書寫代碼,或者添加新的類。一個類庫項目中可以容納的類數目沒有限制,但只有聲明為public 的類可以被外界使用。類庫項目編譯之后,會生成一個動態鏈接庫(DLL:Dynamic Link Library)文件。這就是可以被重用的.NET 軟件組件——程序集。默認情況下,類庫文件名就是項目名加上“.dll”后綴。每個類庫項目都擁有一個默認的命名空間,可以通過類庫項目的屬性窗口來指定。需要仔細區分“類庫項目”、“程序集”和“命名空間”這三個概念的區別:

(1)每個類庫項目編譯之后,將會生成一個程序集。

(2)類庫項目中可以擁有多個類,這些類可屬于不同的命名空間。

(3)不同的類庫項目可以定義相同的命名空間。

根據上述三個特性,可以得到以下結論:“命名空間”是一個邏輯上的概念,它的物理載體是“程序集”,具體體現為“DLL”(或EXE)文件。在Visual Studio 中,可通過創建“類庫”類型的項目生成程序集。一個程序集可以有多個命名空間,而一個命名空間也可以分布于多個程序集。一旦生成了一個程序集,在其他項目中就可以通過添加對這一程序集的引用而使用此程序集中的類。其方法是在“項目”菜單中選擇“添加程序集”命令,激活“瀏覽”卡片,選擇一個現有的程序集文件(DLL 或EXE)。一個項目添加完對特定程序集的引用之后,就可以直接創建此程序集中的類了,當然要注意指明其命名空間。

八、委托

委托是一種新的面向對象語言特性,在歷史比較長的面向對象語言比如C++中并未出現過。微軟公司在設計運行于.NET Framework平臺之上的面向對象語言(如C#和VisualBasic.NET)時引入了這一新特性。委托(delegate)也可以看成是一種數據類型,可以用于定義變量。但它是一種特殊的數據類型,它所定義的變量能接收的數值只能是一個函數,更確切地說,委托類型的變量可以接收一個函數的地址,很類似于C++語言的函數指針。簡單地說:委托變量可看成是一種類型安全的函數指針,它只能接收符合其要求的函數地址。委托可以看成是一個函數的“容器”,將某一具體的函數“裝入”后,就可以把它當成函數一樣使用。定義委托類型時對函數的要求被稱為函數的“簽名(signature)”。函數的簽名規定了函數的參數數目和類型,以及函數的返回值,體現了函數的本質特征。每一個委托都確定了一個函數的簽名。擁有不同簽名的函數不能賦值給同一類型的委托變量。因此,一個委托類型的變量,可以引用任何一個滿足其要求的函數。

1.委托的組合與分解

委托變量可以代表某一函數,使用委托變量就相當于調用一個函數。如果僅是這么簡單,那么直接調用函數不就行了嗎?為什么還要引入“委托”這一特性?事實上,委托不僅可以代表一個函數,還可以組合“一堆”的函數,然后批量執行它們,這樣的委托變量又稱為“多路委托變量”。可以用加法運算符來組合單個委托變量為多路委托變量。類似地,也可以使用減法運算符來從一個多路委托變量中移除某個委托變量。

2.事件與多路委托

事件的主要特點是一對多關聯,即一個事件源,多個響應者。在具體技術上,.NET Framework 的事件處理機制是基于多路委托實現的。事件與多路委托其實大同小異,只不過多路委托允許在事件源對象之外激發事件罷了。所有的.NET Framework 可視化窗體控件的預定義事件,都是某一對應的“事件名+Handler”委托類型的變量。與此事件相關的信息都封裝在“事件名+Args”類型的事件參數中,此事件參數有一個基類EventArgs,它是所有事件參數的基類。明了上述內部機理,對于我們在程序中定義自己的事件非常有好處,尤其是開發一個自定義的可視化控件時,如果需要增加新的事件類型,我們應盡量遵循.NET Framework 的定義事件的框架,給事件取一個名字,定義一個“事件名+Handler”的事件委托類型,再從EventArgs 派生出自定義事件的參數,取名為“事件名+Args”。

面向對象的軟件系統有許多都是事件驅動的,ASP.NET 就采用了“事件驅動”的編程方式。所謂“事件驅動”的開發方式,就是指整個系統包含許多的對象,這些對象可以引發多種事件,軟件工程師的主要開發工作就是針對特定的事件書寫代碼響應它們。.NET 事件處理機制建立在委托的基礎之上,而這兩者都是ASP.NET 技術的基礎之一。因此,必須牢固地掌握好委托和事件這兩種編程技術,才能為掌握ASP.NET 技術掃清障礙。

第四篇:C#總結

引用類型是類型安全的指針,它們的內存是分配在堆(保存指針地址)上的。String、數組、類、接口和委托都是引用類型。

強制類型轉換與as類型轉換的區別:當類型轉換非法時,強制類型轉換將拋出一System.InvalidCastException異常,而as不會拋出異常,它返回一個null值。用using創建別名:using console = System.Console;訪問限定符:

public 該成員可以被其他任何類訪問 protected 該成員只能被其派生類訪問

private 該成員只能被本類的其他成員訪問 internal 該成員只能在當前編譯單元的其他成員訪問 帶參數列表和返回值的Main方法: class Test {

public static int Main(string[] args)

{

foreach(string arg in args)

{

...}

} } 構造函數(constructor)包括實例構造函數和靜態構造函數。構造函數與類名相同,且不能有返回值。例:

class TestClass {

TestClass()//實例構造函數:可以訪問靜態成員和實例成員,用于初始化實例成員

{

...}

static TestClass()//靜態構造函數:只能訪問靜態成員,用于初始化靜態成員

{

...} } 類的靜態成員屬于類所有,不必生成實例就可以訪問,它是在載入包含類的應用程序時創建的,但靜態方法不能訪問類的實例變量和方法。通常,靜態變量是在定義時就賦初始值的。類的實例成員屬于類的實例所有,不創建實例對象就無法對其進行訪問,實例成員可以訪問類的

靜態成員和其它實例成員。調用基類的析構函數: class A {

public A()

{

...} } class B {

public B(): base()//調用基類的析構函數

{

...} } 常量:其值是在編譯時設定的,必須是數值文字。默認狀態下常量是靜態的。例: class A {

public const double pi = 3.1415;} 常量是編譯時就確定的值,只讀字段是在運行才能確定的值。比如運行時才能確定的屏幕分辨率。

只讀字段只能在類的析構函數中賦值。靜態只讀字段: class A {

public static readonly int ScreenWidth;//靜態只讀字段

static A()

//靜態析構函數

{

ScreenWidth = 1024;//在靜態析構函數中初始化

} } 在類的繼承中,類的析構函數是不會被繼承的。一個派生類只能從一個基類繼承,不能同時從多個基類繼承,但可以通過繼承多個接口來達到相同目的。實現多繼承的唯一方法就是使用接口。例:

class MyFancyGrid: Control, ISerializable, IDataBound {...} 密封類是不能繼承的類,抽象類不能被定義為密封類,且密封類的私有成員不能用protected修飾,只能用private。例: sealed class A {...} 關鍵字ref和out用于指定用引用方式傳遞方法的參數。

它們的區別是:ref參數必須初始化,而out參數不需要初始化。所以在方法處理代碼依賴參數的初始化值時使用ref,不依賴初始化值時使用out。對out參數即使在傳遞前對其進行了初始化,其值也不會傳遞到方法處理函數內部。傳遞時系統會將其設為未初始化。所以在方法內部必須對out參數進行初始化。

方法重載時,必須參數數目和參數類型其中之一不同,返回值不同不能作為重載。C#不支持方法的默認值,只能通過方法重載來實現。例: class A {

int Method(int a)

{

...}

void Method(int a, int b)//參數數目不同

{

//返回值不同不能作為重載

...} } params參數用于一個不定數目參數的方法,一般后面跟一個數組。例: class A {

public void Method(params int[] i)

{

...} } 方法的覆蓋:指派生類覆蓋基類的同名方法,有二種方法

1)第一種是在派生類要覆蓋的方法前面加new修飾,而基類不需要作任何改動。這種方法的缺點是不能實現多態。例: class A {

public void Method()//無需任何修飾

{

...} } class B: A

//從基類繼承

{

new public void Method()//覆蓋基類的同名方法

{

...} } class TestClass {

A Instance = new B();

Instance.Method();//這時將調用類A的Method方法,而不是類B的Method方法 } 2)第二種是在派生類要覆蓋的方法前面加override修飾,而基類的同名方法前面加virtual修飾。這樣就能實現多態,例: class A {

virtual public void Method()

//基類定義虛方法

{

//虛擬方法不能定義為private,因為private成員對派生類是無法訪問的...} }

class B: A

//從基類繼承 {

override public void Method()

//派生類覆蓋基類的同名虛方法

{

...} } class TestClass {

protected void Test()

{

A Instance = new B();

//定義一個實例,類型為基類,從派生類創建

//派生類總是能夠向上轉換為其基類

Instance.Method();

//將調用派生類B的Method方法,而不是基類的,這就是多態

} } 說明:new修飾的方法覆蓋不能實現多態的原因,是因為使用new時編譯器只會實現早期綁定(early binding)。即調用的方法在編譯時就決定了:編譯器看到Instance.Method()而Instance的類是A,就會調用類A的Method()方法。

override修飾的方法覆蓋可以實現多態的原因,是因為實現了后期綁定(late binding)。使用override時強制編譯器在運行時根據類的真正類型正確調用相應的方法,而不是在編譯時。

而基類的同名方法必須加virtual修飾。

類的靜態方法可能通過 類名.靜態方法名 這種格式來調用,不能使用 實例名.靜態方法名 這種方法調用。

因為類的靜態方法為類所有(是屬于類本身的),而非實例所有(不是屬于類的實例的)。類的靜態方法可以訪問類的任何靜態成員,但不能訪問類的實例成員。C#中類的變量稱為字段。類的public變量稱為類的公共字段。

類的屬性由一個protected(也可以是private)字段和getter和setter方法構成: class Address {

protected string zipCode;//protected字段,注意大小寫

public string ZipCode

{

get

//getter方法

{

return zipCode;

}

set

//setter方法

{

zipCode = value;//被傳遞的值自動被在這個value變量中

}

};} 只讀屬性是指省略setter方法的屬性,只讀屬性只能讀取,不能設置。

屬性也可以用限定符virtual,override和abstract修飾,功能同其他類的方法。

屬性有一個用處稱為懶惰的初始化(lazy initialization)。即在需要類成員時才對它們進行初始化。如果類中包含了很少被引用的成員,而這些成員的初始化又會花費大量的時候和系統資源的話,懶惰的初始化就很有用了。C#中數組對象共同的基類是System.Array。將數組聲明為類的一個成員時,聲明數組與實例化數組必須分開,這是因為只能在運行時創建了類的實例對象之后,才能實例化數組元素值。聲明:

int[] intArray;//一維數組 int[,] int3Array;//三維數組 初始化:

intArray = new int[3] {1,2,3};int[,] int2Array = new int[2,3] {{1,2,3},{4,5,6}};//聲明時可以初始化 遍歷:

1)一維數組

for(int i = 0;i < intArray.Length;i++);//Array.Length返回數組所有元素的個數 foreach(int i in intArray);for(int i = 0;i < intArray.GetLength(0);i++);//Array.GetLength(0)返回數組第一維的個數 2)多維數組

for(int i = 0;i < int3Array.GetLength(0);i++)//遍歷三維數組

for(int j = 0;j < int3Array.GetLength(1);j++)

for(int k = 0;k < int3Array.GetLength(2);k++)

{

...} 數組的維數就是該數組的秩(Rank)。Array.Rank可以返回數據的秩。鋸齒數組(jagged Array)是元素為數組的數組,例:

int[][] jaggedArray = new int[2][];//包含二個元素,每個元素是個數組 jaggedArray[0] = new int[2];//每個元素必須初始化 jaggedArray[1] = new int[3];for(int i = 0;i < jaggedArray.Length;i++)//遍歷鋸齒數組

for(int j = 0;j < jaggedArray[i].Length;j++)

{

...} 類的屬性稱為智能字段,類的索引器稱為智能數組。由于類本身作數組使用,所以用this作索引器的名稱,索引器有索引參數值。例: using System;using System.Collections;class MyListBox {

protected ArrayList data = new ArrayList();

public object this[int idx] //this作索引器名稱,idx是索引參數

{

get

{

if(idx >-1 && idx < data.Count)

{

return data[idx];

}

else

{

return null;

}

}

set

{

if(idx >-1 && idx < data.Count)

{

data[idx] = value;

}

else if(idx = data.Count)

{

data.Add(value);

}

else

{

//拋出一個異常

}

}

} } 接口是二段不同代碼之間約定,通過約定實現彼此之間的相互訪問。C#并不支持多繼承,但通過接口可實現相同功能。當在接口中指定了實現這個接口的類時,我們就稱這個類“實現了該接口”或“從接口繼承”。一個接口基本上就是一個抽象類,這個抽象類中除了聲明C#類的其他成員類型——例如屬性、事件和索引器之外,只聲明了純虛擬方法。接口中可以包含方法、屬性、索引器和事件——其中任何一種都不是在接口自身中來實現的。例:

interface IExampleInterface {

//property declaration

int testProperty { get;}

//event declaration

event testEvevnt Changed;

//mothed declaration

function void testMothed();

//indexer declaration

string this[int index] { get;set;} } 說明:定義接口時,在方法、屬性、事件和索引器所有這些接口成員都不能用public之類的訪問限定符,因為所有接口成員都是public類型的。因為接口定義了一個約定,任何實現一個接口的類都必須定義那個接口中每一個成員,否則將編譯失敗。例: using System;public class FancyControl {

protected string data;

public string Data

{

get {return this.data;}

set {data = value;}

} } interface IValidate {

bool Validate();//接口方法

} public class MyControl: FancyControl, IValidate {

public MyControl()

{

data = “my control data”;

}

public bool Validate()//實現接口

{

if(data == “my control data”)

return true;

else

return false;

} } class InterfaceApp {

MyControl myControl = new MyControl();

IValidate val =(IValidate)myControl;//可以將一個實現某接口的類,轉換成該接口

bool success = val.Validate();//然后可調用該接口的方法 } 也可以用:bool success = myControl.Validate();這種方法來調用Validate方法,因為Validate在類MyControl中是被定義成public的,如果去除public,Validate方法被隱藏,就不能用這種方法調用了,這樣隱藏接口方法稱為名字隱藏(name hiding)。可以用:類實例 is 接口名 來判斷某個類是否實現了某接口,例: myControl is IValidate //MyControl類的實例myControl是否實現了IValidate接口

當然,也可用as來作轉換,根據轉換結果是否為null來判斷某個類是否實現了某接口,例: IValidate val = myControl as IValidate;if(null == val){...//沒有實現IValidate接口 } else {...//實現了IValidate接口

}

如果一個類從多個接口繼承,而這些接口中如果定義的同名的方法,則實現接口的方法時,必須加接口名來區別,寫成 接口名.方法名。假設Test類從IDataStore和ISerializable二個接口繼承,而這二個接口都有SaveData()方法,實現SaveData()方法時必須寫成: class Test: ISerializable, IDataStore {

void ISerializable.SaveData()

{

...}

void IDataStore.SaveData()

{

...} } 如果一個類從多個接口繼承,為了方便可以定義一個新的接口,這個接口繼續多個接口,然后類直接從這個接口繼承就可以了,這個叫合并接口。例: interface ISaveData: ISerializable, IDataStore { //不需要定義任何方法或成員,只是用作合并 } class Test: ISaveData //只要繼承ISaveData就可以了 {...} C# 操作符優先級(從高到低)

初級操作符()x.y f(x)a[x] x++ x--new typeof sizeof checked unchecked 一元操作符 +位移操作符 << >> 關系操作符 < > <= >= is 等于操作符 == 邏輯與

& 邏輯異或 ^ 邏輯或

| 條件與

&& 條件或

|| 條件操作符 ?: 賦值操作符 = *= /= %= +=-= <<= >>= &= ^= |= 所有的二元操作符除賦值符外都是左聯合的,即從左到右計算。

typeof()運算符可以從一個類名得到一個System.Type對象,而從System.Object對象繼承來的GetType()方法則可從一個類實例來得到一個System.Type對象。例: Type t1 = typeof(Apple);//Apple是一個類名

Apple apple = new Apple();//apple是Apple類的一個實例 Type t2 = apple.GetType();//t1與t2是相同的 通過反射得到一個類的所有成員和方法: Type t = typeof(Apple);string className = t.ToString();//得到類名

MethodInfo[] methods = t.GetMethods();//得到所有方法 foreach(MethodInfo method in methods){ //用method.ToString()得到方法名 } MemberInfo[] members = t.GetMembers();//得到所有成員 foreach(MemberInfo member in members){ //用member.ToString()得到成員名 } sizeof()操作符用來計算值類型變量在內存中占用的字節數(Bytes),并且它只能在unsafe(非安全)

代碼中使用。例:

static unsafe public void ShowSizes(){

int i, j;

j = sizeof(short);

j = sizeof(i);} 盡可能使用復合賦值操作符,它比不用復合賦值操作符的效率高。for語句的語法為:

for(initialization;Boolean-expression;step)

embedded-statement 在initialization和step部份還可以使用逗號操作符,例: for(int i = '0', j = 1;i <= 'xFF';i++, j++)for(int i = 1, j = 1;i < 1000;i += j, j = i!~ ++--true false 二元:+32)/ 9)* 5;

} } 代表的(delegate)目的與C++中的函數指針相同,代表不是在編譯時被定義的,而是在運行時被定義的。

代表主要有二個用途:回調(Callback)和事件處理(event)回調通常用于異步處理和自定義處理。例: class DBManager {

static DBConnection[] activeConnections;

//聲明回調函數

public void delegate EnumConnectionCallback(DBConnection connection);

public static void EnumConnections(EnumConnectionCallback callback)

{

foreach(DBConnection connection in activeConnections)

{

callback(connection);//執行回調函數

}

} } //調用

class DelegateApp {

public static void ActiveConncetionCallback(DBConnection connection)//處理函數

{

...}

public void main()

{

//創建指向具體處理函數的代表實例(新建一個代表,讓它指向具體的處理函數)

DBManager.EmnuConnectionCallback myCallback = new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);

DBManager.EnumConnections(myCallback);

} } //使用靜態代表,上面的調用改為 class DelegateApp {

//創建一個指向處理函數的靜態代表

public static DBManager.EmnuConnectionCallback myCallback

= new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);

public static void ActiveConncetionCallback(DBConnection connection)

{...} public void main()

{

DBManager.EnumConnections(myCallback);

} } //在需要時才創建代表,上面的調用改為

class DelegateApp {

//將創建代表放在屬性的getter方法中

public static DBManager.EmnuConnectionCallback myCallback

{

get

{

retun new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);

}

}

public static void ActiveConncetionCallback(DBConnection connection)

{...} public void main()

{

DelegateApp app = new DelegateApp();//創建應用程序

DBManager.EnumConnections(myCallback);

} } 可以將多個代表整合成單個代表,例: class CompositeDelegateApp {

public static void LogEvent(Part part)

{

...}

public static void EmailPurchasingMgr(Part part)

{

...}

public static void Main()

{

//定義二個代表

InventoryManager.OutOfStockExceptionMethod LogEventCallback

= new InventoryManager.OutOfStockExceptionMethod(LogEvent);

InventoryManager.OutOfStockExceptionMethod EmailPurchasingMgrCallback

= new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);

//整合為一個代表,注意后加的代表先執行(這里是先執行LogEventCallback)

InventoryManager.OutOfStockExceptionMethod onHandExceptionEventsCallback

= EmailPurchasingMgrCallback + LogEventCallback;

//調用代表

InventoryManager mgr = new InventoryManager();

mgr.ProcessInventory(onHandExceptionEventsCallback);

//InventoryManager類的ProcessInventory方法的原型為:

//public void ProcessInventory(OutOfStockExceptionMethod exception);

} } 可以根據需要將多個代表自由地組合成單個代表,例: class CompositeDelegateApp {

//代表指向的處理函數(三個代表三個函數)

public static void LogEvent(Part part)

{

...} public static void EmailPurchasingMgr(Part part){...}

public static void EmailStoreMgr(Part part)

{

...}

public static void Main()

{

//通過數組定義三個代表

InventoryManager.OutOfStockExceptionMethod[] exceptionMethods

= new InventoryManager.OutOfStockExceptionMethod[3];

exceptionMethods[0] = new InventoryManager.OutOfStockExceptionMethod(LogEvent);

exceptionMethods[1] = new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);

exceptionMethods[2] = new InventoryManager.OutOfStockExceptionMethod(EmailStoreMgr);

int location = 1;

//再定義一個代表(用于組合成單代表)

InventoryManager.OutOfStockExceptionMethod compositeDelegate;

//根據需要組合

if(location = 2)

{

compositeDelegate = exceptionMethods[0] + exceptionMethods[1];

}

else

{

compositeDelegate = exceptionMethods[0] + exceptionMethods[2];

}

//調用代表

InventoryManager mgr = new InventoryManager();

mgr.ProcessInventory(compositeDelegate);

} } C#的事件遵循“發布——預訂”的設計模式。在這種模式中,一個類公布能夠出現的所有事件,然后任何的類都可以預訂這些事件。一旦事件產生,運行環境就負責通知每個訂戶事件已經發生了。

當代表作為事件的處理結果時(或者說定義具有代表的事件),定義的代表必須指向二個參數的方法:一個參數是引發事件的對象(發布者),另一個是事件信息對象(這個對象必須從EventArgs類中派生)。例: using System;

class InventoryChangeEventArgs: EventArgs //事件信息對象,從EventArgs類派生 {...//假設定義二個public屬性string Sku和int Change } class InventoryManager

//事件的發布者 {

//聲明代表

public delegate void InventoryChangeEventHander(object source, InventoryChangeEventArgs e);

//發布事件,event關鍵字可將一個代表指向多個處理函數

public event InventoryChangeEventHandler onInventoryChangeHander;

public void UpdateInventory(string sku, int change)

{

if(change == 0)

return;

InventoryChangeEventArgs e = new InventoryChangeEventArgs(sku, change);

//觸發事件

if(onInventoryChangeHandler!= null)//如果有預訂者就觸發

onInventoryChangeHandler(this, e);//執行代表指向的處理函數

} } class InventoryWatcher

//事件的預訂者 {

public InventoryWatcher(InventoryManager mgr)//mgr參數用于聯結發布者

{

this.inventoryManager = mgr;

//預訂事件,用 += 調用多個處理函數

mgr.onInventroyChangeHandler += new InventoryManager.InventoryChangeEventHandler(onInventoryChange);

//事件處理函數

void onInventroyChange(object source, InventroyChangeEventArgs e)

{

...}

InventoryManager inventoryManager;

} } class EventsApp

//主程序 {

public static void Main()

{

InventoryManager inventoryManager = new InventoryManager();

InventoryWatcher inventoryWatcher = new InventoryWatcher(inventoryManager);

inventoryManager.UpdateInventory(“111 006 116”,-2);

inventoryManager.UpdateInventory(“111 006 116”, 5);

} } Microsoft Windows NT和IBM OS/2等操作系統都支持占先型多任務。在占先型多任務執行中,處理器負責

給每個線程分配一定量的運行時間——一個時間片(timeslice)。處理器接著在不同的線程之間進行切換,執行相應的處理。在單處理器的計算機上,并不能真正實現多個線程的同時運行,除非運行在多個處理器 的計算機上。操作系統調度的多線程只是根據分配給每個線程時間片進行切換執行,感覺上就像同時執行。

上下文切換(context switching)是線程運行的一部分,處理器使用一個硬件時間來判斷一個指定線程的時間片何時結束。當這個硬件計時器給出中斷信號時,處理器把當前運行的線程所用的所有寄存器(registers)數據存儲到堆棧中。然后,處理器把堆棧里那些相同的寄存器信息存放到一種被稱為“上下文結構”的數據結構中。當處理器要切換回原來執行的線程時,它反向執行這個過程,利用與該線程相關的上下文結構,在寄存器里重新恢復與這一線程相關的信息。這樣的一個完整過程稱為“上下文切換”。多線程允許應用程序把任務分割為多個線程,它們彼此之間可以獨立地工作,最大限度地利用了處理器時間。using System;using System.Threading;class SimpleThreadApp {

public static void WorkerThreadMethod()//線程的執行體

{

...//執行一些操作

}

public static void Main()

{

//創建一個線程代表指向線程的執行體,ThreadStart是創建新線程必須用到的代表

ThreadStart worker = new ThreadStart(WorkerThreadMethod);

Thread t = new Thread(worker);//用線程代表創建線程

t.Start();

//執行線程

} } 可以通過兩種方式來得到一個Thread對象:一種是通過創建一個新線程來得到,如上例;另一種在正在執行的線程調用靜態的Thread.CurrentThread方法。

靜態方法Thread.Sleep(int ms)可以讓當前線程(它自動調用Thread.CurrentThread)暫停指定毫秒的時間。

如果使用Thread.Sleep(0)那么當前線程將一直處于等待中,直到另一個線程調用這個線程的實例方法Thread.Interrupt方法,等待才會結束。使用Thread.Suspend方法也能掛起線程,Thread.Suspend方法可以被當前線程或其他線程調用,而Thread.Sleep(0)只能由當前線程在執行體中調用。當線程用Thread.Suspend掛起時,必須用Thread.Resume方法恢復。不論Thread.Suspend方法調用了多少次,只要調用Thread.Resume方法一次就可以線程恢復執行。用Thread.Suspend方法并不會阻塞線程,調用立即返回。而Thread.Sleep(0)則會阻塞線程。所以確切地說Thread.Sleep(0)暫停線程,而不是掛起線程。

使用Thread.Abort方法可以終止正在執行的線程。當Thread.Abort方法被調用時,線程不會立即終止執行。運行環境將會等待,直到線程到達文檔中所描述的“安全點”。如果要確保線程已經完全停止,可以使用Thread.Join方法。這是一個同步調用,同步調用意味著直到線程完全停止,調用才會返回。

Thread.Priority屬性用于設置的線程的優先級。其值是Thread.ThreadPriority枚舉值,可以設為Highest, AboveNormal,Normal, BelowNormal, Lowest。缺省值是Thread.ThreadPriority.Normal。

線程的同步是為了解決多個線程同時使用同一對象產生的一些問題。通過同步,可以指定代碼的臨界區(critical section),一次只有一個線程可以進入臨界區。使用System.Monitor類(鎖定與信號量)進行線程同步: using System;using System.Threading;public void SaveData(string text)//線程執行函數或線程執行函數調用的對象的方法 {

...//執行其他一些不需要同步的處理

Monitor.Enter(this);//獲取對象的Monitor鎖

...//執行需要同步的處理

Monitor.Exit(this);//釋放對象的Monitor鎖

...//執行其他一些不需要同步的處理

} 說明:當執行Monitor.Enter方法時。這個方法會試圖獲取對象上的Monitor鎖,如果另一個線程已經擁有了這個鎖,這個方法將會阻塞(block),直到這個鎖被釋放。

也可用C#的lock語句來獲得和釋放一個Monitor鎖。上面同步寫成:public void SaveData(string text)//線程執行函數或線程執行函數調用的對象的方法 {

...//執行其他一些不需要同步的處理

lock(this)//獲取對象的Monitor鎖,代碼塊執行完成后釋放Monitor鎖

{

...//執行需要同步的處理

}

...//執行其他一些不需要同步的處理 } 也可以使用System.Threading名稱空間的Mutex類(互斥類)進行線程同步。與Monitor鎖一樣,一次只有一個線程能獲得一個給定的互斥。但Mutex要慢得多,但它增加了靈活性。例:

using System;using System.Threading;class Database {

Mutex mutex = new Mutex(false);//創建一個互斥,但不立即獲得它

//注意:創建互斥在需要同步的方法之外,實際上它只要創建一個實例

public void SaveData(string text)//需要同步的方法

{

mutex.WaitOne();//等待獲得互斥

...//需要同步的處理

mntex.Close();//釋放互斥

} } Mutex類重載了三個構造函數:

Mutex()

//創建并使創建類立即獲得互斥

Mutex(bool initiallyOwned)

//創建時可指定是否要立即獲得互斥 Mutex(bool initiallyOwned, string muterName)//還可以指定互斥的名稱 Mutex.WaitOne方法也重載了三次: Mutex.WaitOne()

//一直等待

Mutex.WaitOne(TimeSpan time, bool exitContext)//等待TimeSpan指定的時間 Mutex.WaitOne(int milliseconds, bool exitContext)//等待指定的毫秒 線程的用法:

1)并發操作:比如一個程序監視多個COM口,當每個COM接到信息時執行一段處理時。2)復雜長時間操作:一個長時間的復雜操作可能會使界面停滯,停止用戶響應,如果還允許用戶停止它,或者顯示進度條、顯示操作執行進程信息時。

反射(Reflection)就是能夠在運行時查找類型信息,這是因為.NET編譯的可執行(PE)文件中包括MSIL和元數據(metadata)。

反射的中心是類System.Type。System.Type是一個抽象類,代表公用類型系統(Common Type System, CTS)中的一種類型。

using System;using System.Reflection;//反射命名空間,必須引用 public static void Main(string[] args){

int i = 6;

Type t = i.GetType();

//根據實例得到類型

t = Type.GetType(“System.Int32”);//根據類型的字符名稱得到類型

} 通過Assembly類可以得到已經編譯.NET Framework程序的中所有類型,例: using System;using System.Diagnostics;//為了使用Process類 using System.Reflection;//為了使用Assembly類 class GetTypesApp {

protected static string GetAssemblyName(string[] args)

{

string assemblyName;

if(0 == args.Length)//如果參數為空,取當前進程的名稱

{

Process p = Process.GetCurrentProcess();

assemblyName = p.ProcessName + “.exe”;

}

else

assemblyName = args[0];//取第一個參數,即當前運行程序名

return assemblyName;

}

public static void Main(string[] args)

{

string assemblyName = GetAssemblyName(args);

Assembly a = Assembly.LoadFrom(assemblyName);//調用編譯程序集

Type[] types = a.GetTypes();

//得到多個類型

foreach(Type t in types)

//遍歷類型數組

{

...//取得t.FullName,t.BaseType.FullName等類型信息

}

} } 一個應用程序可以包括多個代碼模塊。若要將一個cs文件編譯一個模塊,只要執行下面的命令:

csc /target:module 要編譯的模塊.cs //csc是C Sharp Compiler(C#編譯器)然后在應用程序中using編譯的模塊.cs中的NameSpace即可應用了。要反射應用程序中所有代碼模塊(Module),只要:

Assembly a = Assembly.LoadFrom(assemblyName);//應用程序的物理文件名 Module[] modules = a.GetModules();foreach(Module m in modules){...//顯示m.Name等

} 后期綁定(latebinding),例:

string[] fileNames = Directory.GetFiles(Environment.CurrentDirectory, “*.dll”);foreach(string fileName in fileNames){

Assembly a = Assembly.LoadFrom(fileName);

Type[] types = a.GetTypes();

foreach(Type t in types)

{

if(t.IsSubclassOf(typeof(CommProtocol)))//判斷是否有CommProtocol的派生類

{

object o = Activator.CreateInstance(t);//生成實例

MethodInfo mi = t.GetMethod(“DisplayName”);

mi.Invoke(o, null);

//調用方法

}

} } //帶參數的例子

namespace Programming_CSharp {

using System;

using System.Reflection;

public class Tester

{

public static void Main()

{

Type t = Type.GetType(“System.Math”);

Object o = Activator.CreateInstance(t);

// 定義參數類型

Type[] paramTypes = new Type[1];

paramTypes[0]= Type.GetType(“System.Double”);

MethodInfo CosineInfo = t.GetMethod(“Cos”, paramTypes);

//設置參數數據

Object[] parameters = new Object[1];

parameters[0] = 45;

//執行方法

Object returnVal = CosineInfo.Invoke(o, parameters);

Console.WriteLine(“The cosine of a 45 degree angle {0}”, returnVal);

}

} } 動態生成代碼和動態調用的完整例子: //動態生成代碼的部分 using System;using System.Reflection;using System.Reflection.Emit;//動態生成代碼必須引用 namespace ILGenServer {

public class CodeGenerator

{

public CodeGenerator()

{

currentDomain = AppDomain.CurrentDomain;//得到當前域

assemblyName = new AssemblyName();//從域創建一個程序集

assemblyName.Name = “TempAssembly”;

//得到一個動態編譯生成器,AssemblyBuilerAccess.Run表示只在內存中運行,不能保存

assemblyBuilder = currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilerAccess.Run);

//從編譯生成器得到一個模塊生成器

moduleBuilder = assemblyBuilder.DefineDynamicModule(“TempModule”);

//模塊生成器得到類生成器

typeBuilder = moduleBuilder.DefineType(“TempClass”, TypeAttributes.Public);

//為類添加一個方法

methodBuilder = typeBuilder.DefineMethod(“HelloWord”, MethodAttributes.Public, null, null);

//為方法寫入代碼,生成代碼必須使用到IL生成器

msil = methodBuilder.GetILGenerator();

msil.EmitWriteLine(“Hello World”);msil.Emit(OpCodes.Ret);//最后還需要編譯(build)一下類 t = typeBuilder.CreateType();

}

AppDomain currentDomain;

AssemblyName assemblyName;

AssemblyBuilder assemblyBuilder;

ModuleBuilder moduleBuilder;

TypeBuilder typeBuilder;

MethodBuilder methodBuilder;

ILGenerator msil;

object o;

Type t;

public Type T

{

get

{

return this.t;

}

}

} } //動態調用的部分

using System;using System.Reflection;using ILGenServer;//引用動態生成代碼的類 public class ILGenClientApp {

public static void Main({

CodeGenerator gen = new CodeGenerator();//創建動態生成類

Type t = gen.T;

if(null!= t)

{

object o = Activator.CreateInstance(t);

MethodInfo helloWorld = t.GetMethod(“HelloWorld”);//為調用方法創建一個MethodInfo

if(null!= helloWorld)

{

helloWorld.Invoke(o, null);//調用方法

}

}

} } 調用DLL using System;using System.Runtime.InteropServices;//為了使用DLLImport特性

class PInvokeApp {

[DllImport(“user32.dll”, CharSet=CharSet.Ansi)] //CharSet.Ansi指定Ansi版本的函數(MessageBoxA),CharSet.Unicode指定Unicode版本的函數(MessageBoxW)

static extern int MessageBox(int hWnd, string msg, string caption, int type);//聲明DLL中的函數

//[DllImport(“user32.dll”, EntryPoint=“MessageBoxA”)] //用這種方法使用不同的函數名

//static extern int MsgBox(int hWnd, string msg, string caption, int type);

//[DllImport(“user32.dll”, CharSet=CharSet.Unicode)] //調用Unicode版的DLL函數

//static extern int MessageBox(int hWnd, [MarshalAs(UnmanagedType.LPWStr)]string msg,// [MarshalAs(UnmanagedType.LPWStr)]string caption, int type);//將LPWStr翻譯為string型,缺省情況系統只將LPStr翻譯成string

public static void Main()

{

MessageBox(0, “Hello, World!”, “CaptionString”, 0);//調用DLL中的函數

} } 例2,使用回調: class CallbackApp {

[DllImport(“user32.dll”)]

static extern int GetWindowText(int hWnd, StringBuilder text, int count);

delegate bool CallbackDef(int hWnd, int lParam);

[DllImport(“user32.dll”)]

static extern int EnumWindows(CallbackDef callback, int lParam);

static bool PrintWindow(int hWnd, int lParam)

{

StringBuilder text = new StringBuilder(255);

GetWindowText(hWnd, text, 255);

Console.WriteLine(“Window Caption: {0}”, text);

return true;

}

static void Main()

{

CallbackDef callback = new CallbackDef(PrintWindow);

EnumWindows(callback, 0);

} } 關鍵字unsafe指定標記塊在非控環境中運行。該關鍵字可以用于所有的方法,包括構造函數和屬性,甚至還有方法中的代碼塊。關鍵字fixed負責受控對象的固定(pinning)。Pinning是一種動作,向垃圾收集(Garbage Collector, GC)指定一些不能被移動的對象。為了不在內存中產生碎片,.NET運行環境把對象四處移動,以便于最有效地利用內存。使用fixed后指定對象將不會被移動,所以就可以用指針來訪問它。

C#中只能得到值類型、數組和字符串的指針。在數組的情況下,第一個元素必須是值類型,因為C#實際上是返回一個指向數組第一個元素的指針,而不是返回數組自身。& 取一個變量的內存地址(即指向該變量的指針)* 取指針所指變量的值-> 取成員

例:using System;class UnsafeApp {

public static unsafe void GetValues(int* x, int* y)

{

*x = 6;

*y = 42;

}

public static unsafe void Main()

{

int a = 1;

int b = 2;

GetValues(&a, &b);

} } fixed語法為:fixed(type* ptr = expression)statements其中type也可以為非控類型,也可是void;expression是任何產生一個type指針的表達式;statements是應用的代碼塊。例: fixed(int* f = &foo.x)//foo是Foo類的一個實例,x是Foo類的一個int屬性 {

SetFooValue(f);//SetFooValue方法的定義為unsafe static void SetFooValue(int* x)} 傳統的COM組件可以通過互操作層(COM Interop)與.NET運行環境交互?;ゲ僮鲗犹幚碓谕泄苓\行環境和非托管區域中的COM組件操作之間傳遞所有的消息。

要使COM組件能在.NET環境中使用,必須為COM組件生成元數據。.NET運行環境用元數據層業判斷類型信息。在運行時刻使用類型信息,以便生成RCW(Runtime Callable Wrapper,運行時可調用包裝)。當.NET應用程序與COM對象交互時,RCW處理對COM對象的裝載和調用。RCW還完成許多其他的工作,如管理對象標識、對象生存周期以及接口緩沖區。對象生存周期管理十分關鍵,因為.NET GC把對象到處移動,并且當對象不再使用時,自動處理這些對象。RCW服務告訴.NET,應用程序正與托管.NET組件交互,同時又使非托管COM組件“覺得”COM對象是被傳統的COM客戶端調用的。

為了為COM組件生成元數據包裝,必須使用tlbimp.exe(TypeLib Importer)工具: tlbimp some_COM.tlb /out:som_COM.dll

第五篇:c#讀書筆記

1、.NET平臺包括.NET框架和.NET開發工具等組成部分。.NET框架是整個開發平臺的基礎,包括公共語言運行庫和.NET類庫。.NET開發工具包括Visual Studio.NET集成開發環境和.NET編程語言。.NET框架(.NET Framework)是.NET開發平臺的基礎。.NET框架提供了一個跨語言的、統一的、面向對象的開發和運行環境。

2、在Visual Studio.NET集成開發環境下,可以開發多種不同類型的應用程序。最常見的有以下幾種。

??刂婆_應用程序

。Windows應用程序

。ASP.NET網站

3、開發和運行控制臺應用程序

創建一個控制臺應用程序,主要包含以下步驟:

(1)執行文件—》新建—》項目

(2)打開“新建項目”對話框,在“項目類型”列表中選擇Visual c#節點下的Windows,在“模板”窗格中選擇“控制臺應用程序”項目模板,輸入項目的名稱、位置及

解決方案名稱后,單擊“確定”按鈕。

(3)在打開的.cs文件中編寫代碼。

(4)運行程序。執行“調試”—》啟動調試菜單命令,編譯并運行程序

4、c#程序的基本結構

。using關鍵字的功能是用于導入其它命名空間中定義的類型,包括.NET類庫。例如,代碼中使用的console.readline方法實際上是一個簡寫,其全稱是system.console.readline,但由于在代碼的開始使用using指令引入了system命名空間,所以后面可以直接使用console.readline來進行輸入。

。namespace 即“命名空間”,也稱“名稱空間”。命名空間是Visual Studio.NET中的各種語言使用的一種代碼組織的形式,當編譯一個解決方案時,系統會用項目名稱做名字,生成一個namespace,并把類都放在這個namespace里面。

下載C#學習心得(五篇材料)word格式文檔
下載C#學習心得(五篇材料).doc
將本文檔下載到自己電腦,方便修改和收藏,請勿使用迅雷等下載。
點此處下載文檔

文檔為doc格式


聲明:本文內容由互聯網用戶自發貢獻自行上傳,本網站不擁有所有權,未作人工編輯處理,也不承擔相關法律責任。如果您發現有涉嫌版權的內容,歡迎發送郵件至:645879355@qq.com 進行舉報,并提供相關證據,工作人員會在5個工作日內聯系你,一經查實,本站將立刻刪除涉嫌侵權內容。

相關范文推薦

    C#作業參考答案

    語句while(x>10 && x......

    C#課程設計報告書

    :課程設計報告書 面向對象方法學 課 程 設 計 報 告 設計題目:學生信息管理系統課程 班 級:13軟件工程1班 學 號:20130*** 姓 名:何** 指導教師:莊**老師 設計時間:2014年12月 1 附......

    C#程序設計實驗報告

    實驗報告書寫要求實驗報告原則上要求學生手寫,要求書寫工整。若因課程特點需打印的,標題采用四號黑體,正文采用小四號宋體,單倍行距。紙張一律采用A4的紙張。 實驗報告書寫說明......

    C# 注釋規范

    C# 注釋(Comment)規范 注釋規范包括:模塊(類)注釋規范、類的屬性、方法注釋規范、代碼間注釋 1. 模塊(類)注釋規范 模塊開始必須以以下形式書寫模塊注釋: /// ///模塊編號: ///作用......

    C#實習總結

    現在的社會日新月異,科技飛速發展,但是隨之而來的環境問題也日益嚴重,當然這也有很多其他諸如人口、能源等因素,不過這些讓人們越來越重視綠色產業,而軟件就是首當其沖的一個。我......

    c#基礎總結

    【1】面向對象程序設計語言的三大特點是什么?答:【23】Main函數特點?答:1)Main方法是C#程序的限定,默認的為private【2】三種命名法則的特點?答:匈牙利命名法:在變限定符,返回類型為vo......

    C#心得體會(5篇模版)

    ? C#心得體會10計算機應用1班全博鵬 剛學習C#的時候,感覺很難,做的時候出現很多錯誤而且我是照著書打代碼還有錯誤,那時的感覺是迷茫的。在學習的過程中,我還是堅持下來,雖然學......

    C#期末總結

    C#期末總結 接觸C#已經有半學期時間,對C#感觸頗多。C#作為邏輯性極強,功能強大的程序編程語言,僅僅學習半學期是遠遠不夠的,希望自己能在這條路上不斷前行,能夠活到老學到老。跟......

主站蜘蛛池模板: 国产精品99久久99久久久| 免费看成人aa片无码视频羞羞网| 亚洲欧美综合人成在线| 老司机午夜永久免费影院| 日韩精品一区二区三区vr| 人妻无码久久一区二区三区免费| 精品国产男人的天堂久久| 欧美牲交40_50a欧美牲交aⅴ| 日本少妇被黑人猛cao| 午夜阳光精品一区二区三区| 亚洲va中文字幕| 丁香五月欧美成人| 精品国产aⅴ一区二区三区| 黑人巨大精品欧美黑寡妇| 果冻传媒2021精品一区| 熟妇人妻中文字幕| 亚洲一区二区三区日本久久九| 99re6这里有精品热视频| 午夜家庭影院| 国产亚洲精品久久久久久禁果tv| 亚洲中文无码av永久| 免费视频好湿好紧好大好爽| 国产精品aⅴ视频在线播放| 中国熟妇浓毛hdsex| 久久人妻精品白浆国产| 99成人国产综合久久精品| 精品人妻中文字幕有码在线| 久久亚洲国产精品亚洲老地址| 上司人妻互换中文字幕| 538在线精品视频| 四虎永久在线精品免费网站| 国产欧美日韩精品丝袜高跟鞋| 久久av无码精品人妻出轨| 天天躁夜夜躁狠狠久久成人网| 伊人久久无码大香线蕉综合| 天天狠天天天天透在线| 午夜精品乱人伦小说区| 久久视频在线视频精品| 少妇厨房愉情理伦片免费| 国产亚洲日韩a欧美在线人成| 无码人妻久久1区2区3区|