大話C#語言——高階教程總結
推薦閱讀:
特性
用於在執行時傳遞程式中各種元素(比如類、方法、結構、列舉、元件等)的行為資訊的宣告性標籤。
Net 框架提供了三種預定義特性:
AttributeUsage
Conditional
Obsolete
反射
反射指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。
程式集包含模組,而模組包含型別,型別又包含成員。反射則提供了封裝程式集、模組和型別的物件。
反射(Reflection)有下列用途:
它允許在執行時檢視特性(attribute)資訊。
它允許審查集合中的各種型別,以及例項化這些型別。
它允許延遲繫結的方法和屬性(property)。
它允許在執行時建立新型別,然後使用這些型別執行一些任務。
屬性
使用 訪問器(accessors) 讓私有域的值可被讀寫或操作。例如:有一個名為 Student 的類,帶有 age私有域。我們不能在類的範圍以外直接訪問這些域,但是我們可以擁有訪問這些私有域的屬性。
程式碼實現如下:
using System;
namespace 屬性
{
class Student
{
private int age = 0;
// 宣告型別為 int 的 Age 屬性
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
}
class ExampleDemo
{
public static void Main()
{
// 建立一個新的 Student 物件
Student s = new Student();
s.Age = 9; //9
// 增加年齡
s.Age += 1; //10
Console.ReadKey();
}
}
}
索引器
允許一個物件可以像陣列一樣被索引。當為類定義一個索引器時,該類的行為就會像一個虛擬陣列(virtual array) 一樣。可以使用陣列訪問運算子 [ ] 來訪問該類的例項。
格式如下:
//索引器定義的時候帶有 this 關鍵字,它指向物件例項
element-type this[int index]
{
// get 訪問器
get
{
// 返回 index 指定的值
}
// set 訪問器
set
{
// 設定 index 指定的值
}
}
下面舉個例子來看看索引器如何使用:
using System;
namespace 索引器
{
class IndexedNames
{
private string[] namelist = new string[size];
static public int size = 10;
//初始化每個元素的值
public IndexedNames()
{
for (int i = 0; i < size; i++)
namelist[i] = "N. A.";
}
public string this[int index]
{
//取值,輸出時用到
get
{
string tmp;
if( index >= 0 && index <= size-1 )
{
tmp = namelist[index];
}
else
{
tmp = "";
}
return ( tmp );
}
//設定值,重置值得時候使用
set
{
if( index >= 0 && index <= size-1 )
{
namelist[index] = value;
}
}
}
static void Main(string[] args)
{
IndexedNames names = new IndexedNames();
names[0] = "被重置後的值";
for ( int i = 0; i < IndexedNames.size; i++ )
{
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
}
}
上面程式碼在這裡就不做過多的解釋了,註釋已經在程式碼中標註。
委託
C# 中的委託(Delegate)類似於 C 或 C++ 中函式的指標。委託(Delegate) 是存有對某個方法的引用的一種引用型別變數。派生自 System.Delegate 類。
格式:
[訪問修飾符] delegate <return type> <delegate-name> <parameter list>
例如:
public delegate int MyDelegate (string s);
使用方法:
using System;
delegate int NumberChanger(int n);
namespace 委託
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 建立委託例項
NumberChanger nc1 = new NumberChanger(AddNum);
// 使用委託物件呼叫方法
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
委託的多播:委託物件可使用 “+” 運算子進行合併。只有相同型別的委託可被合併。
例如:
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 建立委託例項
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1; //15
nc += nc2; //15*5=75
// 呼叫多播
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
下面再舉一個委託多播例項:例如小明叫小張買完車票,之後接著又讓他帶張電影票
// 小張類
public class MrZhang
{
// 其實買車票的悲情人物是小張
public static void BuyTicket()
{
Console.WriteLine("NND,每次都讓我去買票,雞人呀!");
}
public static void BuyMovieTicket()
{
Console.WriteLine("我去,自己泡妞,還要讓我帶電影票!");
}
}
//小明類
class MrMing
{
// 宣告一個委託,其實就是個“命令”
public delegate void BugTicketEventHandler();
public static void Main(string[] args)
{
// 這裡就是具體闡述這個命令是幹什麼的,本例是MrZhang.BuyTicket“小張買車票”
BugTicketEventHandler myDelegate = new BugTicketEventHandler(MrZhang.BuyTicket);
myDelegate += MrZhang.BuyMovieTicket;
// 這時候委託被附上了具體的方法
myDelegate();
Console.ReadKey();
}
}
事件
事件(Event) 基本上說是一個使用者操作,如按鍵、點選、滑鼠移動等等,或者是一些出現,如系統生成的通知。事件使用 釋出-訂閱(publisher-subscriber) 模型。包含事件的類用於釋出事件。這被稱為 釋出器(publisher) 類。其他接受該事件的類被稱為 訂閱器(subscriber) 類。
釋出器(publisher) 是一個包含事件和委託定義的物件。事件和委託之間的聯絡也定義在這個物件中。釋出器(publisher)類的物件呼叫這個事件,並通知其他的物件。
訂閱器(subscriber) 是一個接受事件並提供事件處理程式的物件。在釋出器(publisher)類中的委託呼叫訂閱器(subscriber)類中的方法(事件處理程式)。
通過事件使用委託:在類的內部宣告事件,首先必須宣告該事件的委託型別。然後,宣告事件本身,使用 event 關鍵字。
例如:宣告一個myDelegate委託,然後宣告一個BoilerEventLog事件
//宣告委託
public delegate void myDelegate();
// 基於上面的委託定義事件
public event BoilerLogHandler BoilerEventLog;
例如:在名稱空間“通過事件使用委託”中,建立EventTest類作為釋出器,並宣告myDelegate委託和ChangeNum事件;建立subscribEvent類作為訂閱器類;建立MainClass類,註冊事件。
using System;
namespace 通過事件使用委託
{
/***********釋出器類***********/
public class EventTest
{
private int value;
//委託
public delegate void myDelegate();
//事件
public event myDelegate ChangeNum;
//建構函式
public EventTest()
{
int n = 5;
SetValue( n );
}
protected void OnNumChanged()
{
if ( ChangeNum != null )
{
//有事件
ChangeNum(); /* 事件被觸發 */
}else {
//沒有事件
Console.WriteLine( "event not fire" );
Console.ReadKey(); /* 回車繼續 */
}
}
//設定值,並觸發事件
public void SetValue( int n )
{
if ( value != n )
{
value = n;
OnNumChanged();
}else{
Console.WriteLine( "值相等" );
Console.ReadKey(); /* 回車繼續 */}
}
}
/***********訂閱器類***********/
public class subscribEvent
{
public void printf()
{
Console.WriteLine( "event fire" );
Console.ReadKey(); /* 回車繼續 */
}
}
/***********觸發***********/
public class MainClass
{
public static void Main()
{
EventTest e = new EventTest(); /* 例項化物件,第一次沒有觸發事件(事件為空) */
subscribEvent v = new subscribEvent(); /* 例項化訂閱器 */
e.ChangeNum += new EventTest.myDelegate( v.printf ); /* 註冊事件 */
e.SetValue( 7 );
e.SetValue( 10 );
}
}
}
集合
在 C# 中,集合繼承自System.Collection;在 C# 中,Object 類是所有資料型別的基類
1.動態陣列(ArrayList):可以替代一個數組。與陣列不同的是,可以使用索引在指定的位置新增和移除。
ArrayList al = new ArrayList();
al.Add(45);
2.雜湊表(Hashtable)儲存:鍵/值對,使用鍵來訪問集合中的元素。
Hashtable ht = new Hashtable();
ht.Add("001", "小木遊戲");
3.排序列表(SortedList):集合中的各項總是按鍵值排序排序,是陣列和雜湊表的組合,儲存鍵/值對,使用鍵和索引來訪問集合中的元素。如果使用索引訪問各項,則它是一個動態陣列(ArrayList),如果使用鍵訪問各項,則它是一個雜湊表(Hashtable)。
SortedList sl = new SortedList();
sl.Add("001", "小木遊戲");
sl.Add("001", "小木子");
Console.WriteLine( sl[0]);//小木遊戲
4.堆疊(Stack):後進先出
Stack st = new Stack();
st.Push('小木');
st.Push('遊戲');
st.Pop();//遊戲
st.Pop();//小木
5.佇列(Queue):先進先出
Queue q = new Queue();
q.Enqueue('小木');
q.Enqueue('遊戲');
char ch1 = (char)q.Dequeue();//小木
char ch2 = (char)q.Dequeue();//遊戲
6.點陣列(BitArray):使用布林值來表示,其中 true 表示位是開啟的(1),false 表示位是關閉的(0)。當需要儲存位,但是事先不知道位數時,則使用點陣列
// 建立兩1個大小為 8 的點陣列
BitArray ba1 = new BitArray(8);
byte[] a = { 60 };
for (int i = 0; i < ba1.Count; i++)
{
Console.Write("{0, -6} ", ba1[i]);//False False True True True True False False
}
上面輸出結果為將60的二進位制數,轉換成對應的布林值。
泛型
在封裝公共元件的時候,很多時候我們的類/方法不需要關注呼叫者傳遞的實體是"什麼",這個時候就可以使用泛型。
泛型方法:
//交換函式
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a = 10;
int b = 20;
char c = 'I';
char d = 'V';
// 呼叫 swap
Swap<int>(ref a, ref b);
Swap<char>(ref c, ref d);
Console.ReadKey();
}
泛型委託:
delegate T NumberChanger<T>(T n);
// 建立委託例項
NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
匿名方法
匿名方法是通過使用 delegate 關鍵字建立委託例項來宣告的
例如:
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
Console.WriteLine("Anonymous Method: {0}", x);
};
下面舉個例子,使用兩種方法建立委託:
using System;
delegate void NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static void AddNum(int p)
{
num += p;
Console.WriteLine("Named Method: {0}", num);
}
static void Main(string[] args)
{
///////////////方法一
// 使用匿名方法建立委託例項
NumberChanger nc = delegate(int x)
{
Console.WriteLine("Anonymous Method: {0}", x);
};
// 使用匿名方法呼叫委託
nc(10);
//////////////方法二
// 使用命名方法例項化委託
nc = new NumberChanger(AddNum);
// 使用命名方法呼叫委託
nc(5);
Console.ReadKey();
}
}
}
不安全程式碼
不安全程式碼或非託管程式碼是指使用了指標變數的程式碼塊。當一個程式碼塊使用 unsafe 修飾符標記時,C# 允許在函式中使用指標變數
例如:在函式返回型別前加上關鍵字unsafe ,函式中便可以使用指標。
public unsafe void swap(int* p, int *q)
{
int temp = *p;
*p = *q;
*q = temp;
}
多執行緒
執行緒是輕量級程序。一個使用執行緒的常見例項是現代作業系統中並行程式設計的實現。為了同時執行多個任務,它可以被劃分為更小的執行緒。
執行緒生命週期開始於 System.Threading.Thread 類的物件被建立時,結束於執行緒被終止或完成執行時。
執行緒生命週期中的各種狀態:
1.未啟動狀態:當執行緒例項被建立但 Start 方法未被呼叫時的狀況。
2.就緒狀態:當執行緒準備好執行並等待 CPU 週期時的狀況。
3.不可執行狀態:下面的幾種情況下執行緒是不可執行的:
已經呼叫 Sleep 方法
已經呼叫 Wait 方法
通過 I/O 操作阻塞
4.死亡狀態:當執行緒已完成執行或已中止時的狀況。
程序中第一個被執行的執行緒稱為主執行緒。當 C# 程式開始執行時,主執行緒自動建立。使用 Thread 類的 CurrentThread 屬性訪問執行緒。
1.建立執行緒用Thread :
Thread childThread = new Thread(“主執行緒名”);
注意:這種方法是建立子執行緒,因為主執行緒在程式開始時自動被建立
2.暫停執行緒用 sleep() 方法:
Thread.Sleep(暫停時間);
3.銷燬執行緒用Abort()方法:
執行緒名.Abort();