今天在一個網站看到了一篇關於C#基礎知識的文章篇幅很長浏覽了一下確實是基礎知識雖然順序凌亂沒有章法但是對於我們經常寫代碼的人確實應該盡量多的記住一些基礎知識 掌握牢固的基礎知識編程才能得心應手最基本的東西也應該注重因為細節決定成敗
引用類型是類型安全的指針它們的內存是分配在堆(保存指針地址)上的
string數組類接口和委托都是引用類型
強制類型轉換與as類型轉換的區別當類型轉換非法時強制類型轉換將拋出一個systeminvalidcastexception異常而as不會拋出異常它返回一個null值
用using創建別名
view plainprint?
using console = nsole訪問限定符public 該成員可以被其他任何類訪問protected 該成員只能被其派生類訪問private 該成員只能被本類的其他成員訪問internal 該成員只能在當前編譯單元的其他成員訪問
帶參數列表和返回值的main方法
view plainprint?
class test { public static int main(string[] args)
{ foreach (string arg in args)
{……
}構造函數(constructor)包括實例構造函數和靜態構造函數
構造函數與類名相同且不能有返回值例
view plainprint?
class testclass { testclass() //實例構造函數可以訪問靜態成員和實例成員用於初始化實例成員{……
}
static testclass() //靜態構造函數只能訪問靜態成員用於初始化靜態成員{……
}類的靜態成員屬於類所有不必生成實例就可以訪問它是在載入包含類的應用程序時創建的但靜態方法不能訪問類的實例變量和方法通常靜態變量是在定義時就賦初始值的
類的實例成員屬於類的實例所有不創建實例對象就無法對其進行訪問實例成員可以訪問類的靜態成員和其它實例成員
調用基類的析構函數
view plainprint?
class a { public a()
{……
}
class b { public b() base() //調用基類的析構函數{……
}常量其值是在編譯時設定的必須是數值文字默認狀態下常量是靜態的例
view plainprint?
class a { public const double pi = }常量是編譯時就確定的值只讀字段是在運行才能確定的值比如運行時才能確定的屏幕分辨率
只讀字段只能在類的析構函數中賦值
靜態只讀字段
view plainprint?
class a { public static readonly int screenwidth //靜態只讀字段static a() //靜態析構函數{ screenwidth = //在靜態析構函數中初始化}在類的繼承中類的析構函數是不會被繼承的
一個派生類只能從一個基類繼承不能同時從多個基類繼承但可以通過繼承多個接口來達到相同目的實現多繼承的唯一方法就是使用接口例
view plainprint?
class myfancygrid control iserializable idatabound {……
}密封類是不能繼承的類抽象類不能被定義為密封類且密封類的私有成員不能用protected修飾只能用private例
view plainprint?
sealed class a {……
}關鍵字ref和out用於指定用引用方式傳遞方法的參數
它們的區別是ref參數必須初始化而out參數不需要初始化所以在方法處理代碼依賴參數的初始化值時使用ref不依賴初始化值時使用out對out參數即使在傳遞前對其進行了初始化其值也不會傳遞到方法處理函數內部傳遞時系統會將其設為未初始化所以在方法內部必須對out參數進行初始化
方法重載時必須參數數目和參數類型其中之一不同返回值不同不能作為重載
c#不支持方法的默認值只能通過方法重載來實現例
view plainprint?
class a { int method(int a)
{……
}
void method(int a int b) //參數數目不同{ //返回值不同不能作為重載……
} view plainprint?
params參數用於一個不定數目參數的方法一般後面跟一個數組例class a { public void method(params int[] i)
{……
}方法的覆蓋指派生類覆蓋基類的同名方法有二種方法)第一種是在派生類要覆蓋的方法前面加new修飾而基類不需要作任何改動
這種方法的缺點是不能實現多態例
view plainprint?
class a { public void method() //無需任何修飾{……
}
class b a //從基類繼承{ new public void method() //覆蓋基類的同名方法{……
}
class testclass { a instance = new b()thod() //這時將調用類a的method方法而不是類b的method方法} )第二種是在派生類要覆蓋的方法前面加override修飾而基類的同名方法前面加virtual修飾
這樣就能實現多態例
view plainprint?
class a { virtual public void method() //基類定義虛方法{ //虛擬方法不能定義為private因為private成員對派生類是無法訪問的……
}
class b a //從基類繼承{ override public void method() //派生類覆蓋基類的同名虛方法{……
}
class testclass { protected void test()
{ a instance = new b() //定義一個實例類型為基類從派生類創建//派生類總是能夠向上轉換為其基類thod() //將調用派生類b的method方法而不是基類的這就是多態}說明new修飾的方法覆蓋不能實現多態的原因是因為使用new時編譯器只會實現早期綁定(early binding)
即調用的方法在編譯時就決定了編譯器看到thod()而instance的類是a就會調用類a的method()方法
override修飾的方法覆蓋可以實現多態的原因是因為實現了後期綁定(late binding)
使用override時強制編譯器在運行時根據類的真正類型正確調用相應的方法而不是在編譯時
而基類的同名方法必須加virtual修飾
類的靜態方法可能通過 類名靜態方法名 這種格式來調用不能使用 實例名靜態方法名 這種方法調用
因為類的靜態方法為類所有(是屬於類本身的)而非實例所有(不是屬於類的實例的)
類的靜態方法可以訪問類的任何靜態成員但不能訪問類的實例成員
c#中類的變量稱為字段類的public變量稱為類的公共字段
類的屬性由一個protected(也可以是private)字段和getter和setter方法構成
view plainprint?
class address { protected string zipcode //protected字段注意大小寫public string zipcode { get //getter方法{ return zipcode} set //setter方法{ zipcode = value //被傳遞的值自動被在這個value變量中} }}只讀屬性是指省略setter方法的屬性只讀屬性只能讀取不能設置
屬性也可以用限定符virtualoverride和abstract修飾功能同其他類的方法
屬性有一個用處稱為懶惰的初始化(lazy initialization)即在需要類成員時才對它們進行初始化如果類中包含了很少被引用的成員而這些成員的初始化又會花費大量的時候和系統資源的話懶惰的初始化就很有用了
c#中數組對象共同的基類是systemarray將數組聲明為類的一個成員時聲明數組與實例化數組必須分開這是因為只能在運行時創建了類的實例對象之後才能實例化數組元素值
聲明
view plainprint?
int[] intarray //一維數組int[] intarray //三維數組初始化
view plainprint?
intarray = new int[] {}int[] intarray = new int[] {{}{}} //聲明時可以初始化遍歷)一維數組
view plainprint?
for (int i = i < intarraylength i++) //arraylength返回數組所有元素的個數foreach (int i in intarray)for (int i = i < intarraygetlength() i++)//arraygetlength()返回數組第一維的個數)多維數組
view plainprint?
for (int i = i < intarraygetlength() i++) //遍歷三維數組for (int j = j < intarraygetlength() j++)
for (int k = k < intarraygetlength() k++)
{……
}數組的維數就是該數組的秩(rank)arrayrank可以返回數據的秩
鋸齒數組(jagged array)是元素為數組的數組例
view plainprint?
int[][] jaggedarray = new int[][] //包含二個元素每個元素是個數組jaggedarray[] = new int[] //每個元素必須初始化jaggedarray[] = new int[]for (int i = i < jaggedarraylength i++) //遍歷鋸齒數組for (int j = j < jaggedarray[i]length j++)
{……
}類的屬性稱為智能字段類的索引器稱為智能數組由於類本身作數組使用所以用this作索引器的名稱索引器有索引參數值例
view plainprint?
using systemusing llections
class mylistbox { protected arraylist data = new arraylist()public object this[int idx] //this作索引器名稱idx是索引參數{ get { if (idx > && idx < unt)
{ return data[idx]} else { return null} set { if (idx > && idx < unt)
{ data[idx] = value} else if (idx = unt)
{ dataadd(value)} else { //拋出一個異常}接口是二段不同代碼之間約定通過約定實現彼此之間的相互訪問
c#並不支持多繼承但通過接口可實現相同功能
當在接口中指定了實現這個接口的類時我們就稱這個類實現了該接口或從接口繼承
一個接口基本上就是一個抽象類這個抽象類中除了聲明c#類的其他成員類型??例如屬性事件和索引器之外只聲明了純虛擬方法
接口中可以包含方法屬性索引器和事件??其中任何一種都不是在接口自身中來實現的例
view plainprint?
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類型的
因為接口定義了一個約定任何實現一個接口的類都必須定義那個接口中每一個成員否則將編譯失敗例
view plainprint?
using systempublic class fancycontrol { protected string datapublic string data { get {return thisdata} 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 trueelse return false}
class interfaceapp { mycontrol mycontrol = new mycontrol()
ivalidate val = (ivalidate)mycontrol //可以將一個實現某接口的類轉換成該接口bool success = valvalidate() //然後可調用該接口的方法}也可以用
view plainprint?
bool success = mycontrolvalidate()這種方法來調用validate方法因為validate在類mycontrol中是被定義成public的如果去除publicvalidate方法被隱藏就不能用這種方法調用了這樣隱藏接口方法稱為名字隱藏(name hiding)
可以用類實例 is 接口名 來判斷某個類是否實現了某接口例mycontrol is ivalidate //mycontrol類的實例mycontrol是否實現了ivalidate接口當然也可用as來作轉換根據轉換結果是否為null來判斷某個類是否實現了某接口例
view plainprint?
ivalidate val = mycontrol as ivalidateif (null == val)
{…… //沒有實現ivalidate接口} else {…… //實現了ivalidate接口}如果一個類從多個接口繼承而這些接口中如果定義的同名的方法則實現接口的方法時必須加接口名來區別寫成 接口名方法名假設test類從idatastore和iserializable二個接口繼承而這二個接口都有savedata()方法實現savedata()方法時必須寫成
view plainprint?
class test iserializable idatastore { void iserializablesavedata()
{……
}
void idatastoresavedata()
{……
}如果一個類從多個接口繼承為了方便可以定義一個新的接口這個接口繼續多個接口然後類直接從這個接口繼承就可以了這個叫合並接口例
view plainprint?
interface isavedata iserializable idatastore { //不需要定義任何方法或成員只是用作合並} class test isavedata //只要繼承isavedata就可以了{……
} c# 操作符優先級(從高到低)
初級操作符 () xy f(x) a[x] x++ x—— new typeof sizeof checked unchecked一元操作符 + | ~ ++x ——x (t)x乘除操作符 * / %加減操作符 + 位移操作符 << >>關系操作符 < > <= >= is等於操作符 ==邏輯與 &邏輯異或 ^邏輯或 |條件與 &&條件或 ||條件操作符 ?賦值操作符 = *= /= %= += = <<= >>= &= ^= |=
所有的二元操作符除賦值符外都是左聯合的即從左到右計算
typeof()運算符可以從一個類名得到一個systemtype對象而從systemobject對象繼承來的gettype()方法則可從一個類實例來得到一個systemtype對象例
view plainprint?
type t = typeof(apple) //apple是一個類名apple apple = new apple() //apple是apple類的一個實例type t = applegettype() //t與t是相同的通過反射得到一個類的所有成員和方法
view plainprint?
type t = typeof(apple)string classname = ttostring() //得到類名methodinfo[] methods = tgetmethods() //得到所有方法foreach (methodinfo method in methods)
{ //用methodtostring()得到方法名} memberinfo[] members = tgetmembers() //得到所有成員foreach (memberinfo member in members)
{ //用membertostring()得到成員名} sizeof()操作符用來計算值類型變量在內存中占用的字節數(bytes)並且它只能在unsafe(非
安全)
代碼中使用例
view plainprint?
static unsafe public void showsizes()
{ int i jj = sizeof(short)j = sizeof(i)}盡可能使用復合賦值操作符它比不用復合賦值操作符的效率高
for語句的語法為
view plainprint?
for (initialization booleanexpression step)
embeddedstatement在initialization和step部份還可以使用逗號操作符例
view plainprint?
for (int i = j = i <= \xff i++ j++)
for (int i = j = i < i += j j = i j) //輸出斐波那契數列consolewrite({} i)在switch語句中執行一個分支的代碼後還想執行另一個分支的代碼可以用goto case 分支
操作符重載是為了讓程序更加自然容易理解想要為一個類重新定義一個操作符使用以下語法public static 返回值 operator 操作符 (操作對象[操作對象])
說明)所有重載的操作符方法都必須定義為public和static )從技術上說返回值可以是任何類型但通常是返回所定義方法使用的類型)操作對象的數目取決於重載是一元操作符還是二元操作符一元操作符只要一個操作對象二元操作符則需要二個
)不管重載是一元操作符還是二元操作符第一個操作對象的類型都必須與返回值的類型一致而對於二元操作符的第二個操作對象的類型則可以是任何類型
)只有下列操作符可以被重載一元+ ! ~ ++ —— true false二元+ * / % & | ^ << >> == != > < >= <=賦值操作符(+==*/=%=等等)無法被重載
[]和()操作符也無法被重載
)操作符的優先級是無法改變的運算優先級的規則是靜態的
例假設一個invoice發票類由多個invoicedetailline類(成員只有一個double類型的amount金額屬性)組成我們重載+操作符使之可以將invoicedetailline類的內容(注意不是金額合計)加在一起
view plainprint?
class invoice { public arraylist detailline
public invoice //類的析構函數{ detailline = new arraylist() //arraylist存放多個invoicedetailline類的實例}
public static invoice operator+ (invoice invoice invoice invoice) //參數與返回值的類型一致{ //invoice與invoice的內容合並invoice returninvoice = new invoice()foreach(invoicedetailline detailline in invoicedetaillines)
returninvoicedetaillineadd(detailline)foreach(invoicedetailline detailline in invoicedetaillines)
returninvoicedetaillineadd(detailline)return returninvoice}
class invoiceaddapp //調用示例{ public static void main()
{ invoice i = new invoice()for(int i = i < i++)
idetaillineadd(new invoicedetailline(i + ))
invoice i = new invoice()for(int i = i < i++)
idetaillineadd(new invoicedetailline(i + ))
invoice summaryinvoice = i + i //調用重載的操作符+方法}自定義類型轉換可以編寫代碼實際二個不同的類結構體之間的轉換
語法public static implicite/explicite operator 輸出類型 (輸入類型)
說明)轉換方法必須是靜態的
)implicite表示隱式轉換explicite表示顯式轉換
)輸入類型和輸出類型其中之一必須與包含轉換的類或結構體類型即轉換必須與本類相關
例
view plainprint?
struct celisus { public float t
public celisus(float t)
{ thist = t //thist是結構體的字段t是參數}
public static implicite operator celisus(float t) //float=>celisus { return new celisus(t)}
public static implicite operator float(celisus c) //celisus=>float { return ((ct ) / Array) * }代表的(delegate)目的與c++中的函數指針相同代表不是在編譯時被定義的而是在運行時被定義的
代表主要有二個用途回調(callback)和事件處理(event)
回調通常用於異步處理和自定義處理例
view plainprint?
class dbmanager { static dbconnection[] activeconnections//聲明回調函數public void delegate enumconnectioncallback(dbconnection connection)
public static void enumconnections(enumconnectioncallback callback)
{ foreach (dbconnection connection in activeconnections)
{ callback(connection) //執行回調函數} //調用
view plainprint?
class delegateapp { public static void activeconncetioncallback(dbconnection connection) //處理函數{……
}
public void main()
{ //創建指向具體處理函數的代表實例(新建一個代表讓它指向具體的處理函數)
dbmanageremnuconnectioncallback mycallback = new dbmanageremnuconnectioncallback(activeconncetioncallback)dbmanagerenumconnections(mycallback)} //使用靜態代表上面的調用改為
view plainprint?
class delegateapp { //創建一個指向處理函數的靜態代表public static dbmanageremnuconnectioncallback mycallback = new dbmanageremnuconnectioncallback(activeconncetioncallback)public static void activeconncetioncallback(dbconnection connection)
{……
}
public void main()
{ dbmanagerenumconnections(mycallback)} //在需要時才創建代表上面的調用改為
view plainprint?
class delegateapp { //將創建代表放在屬性的getter方法中public static dbmanageremnuconnectioncallback mycallback { get { retun new dbmanageremnuconnectioncallback(activeconncetioncallback)} public static void activeconncetioncallback(dbconnection connection)
{……
}
public void main()
{ delegateapp app = new delegateapp() //創建應用程序dbmanagerenumconnections(mycallback)}可以將多個代表整合成單個代表例
view plainprint?
class compositedelegateapp { public static void logevent(part part)
{……
}
public static void emailpurchasingmgr(part part)
{……
}
public static void main()
{ //定義二個代表inventorymanageroutofstockexceptionmethod logeventcallback = new inventorymanageroutofstockexceptionmethod(logevent)inventorymanageroutofstockexceptionmethod emailpurchasingmgrcallback = new inventorymanageroutofstockexceptionmethod(emailpurchasingmgr)//整合為一個代表注意後加的代表先執行(這裡是先執行logeventcallback)
inventorymanageroutofstockexceptionmethod onhandexceptioneventscallback = emailpurchasingmgrcallback + logeventcallback//調用代表inventorymanager mgr = new inventorymanager()mgrprocessinventory(onhandexceptioneventscallback)//inventorymanager類的processinventory方法的原型為//public void processinventory(outofstockexceptionmethod exception)}可以根據需要將多個代表自由地組合成單個代表例
view plainprint?
class compositedelegateapp { //代表指向的處理函數(三個代表三個函數)
public static void logevent(part part)
{……
}
public static void emailpurchasingmgr(part part)
{……
}
public static void emailstoremgr(part part)
{……
}
public static void main()
{ //通過數組定義三個代表inventorymanageroutofstockexceptionmethod[] exceptionmethods = new inventorymanageroutofstockexceptionmethod[]exceptionmethods[] = new inventorymanageroutofstockexceptionmethod(logevent)exceptionmethods[] = new inventorymanageroutofstockexceptionmethod(emailpurchasingmgr)exceptionmethods[] = new inventorymanageroutofstockexceptionmethod(emailstoremgr)
int location = //再定義一個代表(用於組合成單代表)
inventorymanageroutofstockexceptionmethod compositedelegate//根據需要組合if (location = )
{ compositedelegate = exceptionmethods[] + exceptionmethods[]} else { compositedelegate = exceptionmethods[] + exceptionmethods[]} //調用代表inventorymanager mgr = new inventorymanager()mgrprocessinventory(compositedelegate)} c#的事件遵循發布??預訂的設計模式在這種模式中一個類公布能夠出現的所有事件然後任何的類都可以預訂這些事件一旦事件產生運行環境就負責通知每個訂戶事件已經發生了
當代表作為事件的處理結果時(或者說定義具有代表的事件)定義的代表必須指向二個參數的方法一個參數是引發事件的對象(發布者)另一個是事件信息對象(這個對象必須從eventargs類中派生)
例
view plainprint?
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 == )
returninventorychangeeventargs e = new inventorychangeeventargs(sku change)//觸發事件if (oninventorychangehandler != null) //如果有預訂者就觸發oninventorychangehandler(this e) //執行代表指向的處理函數}
class inventorywatcher //事件的預訂者{ public inventorywatcher(inventorymanager mgr) //mgr參數用於聯結發布者{ thisinventorymanager = mgr//預訂事件用 += 調用多個處理函數mgroninventroychangehandler += new inventorymanagerinventorychangeeventhandler(oninventorychange)//事件處理函數void oninventroychange(object source inventroychangeeventargs e)
{……
}
inventorymanager inventorymanager}
class eventsapp //主程序{ public static void main()
{ inventorymanager inventorymanager = new inventorymanager()inventorywatcher inventorywatcher = new inventorywatcher(inventorymanager)
inventorymanagerupdateinventory( )inventorymanagerupdateinventory( )} microsoft windows nt和ibm os/等操作系統都支持占先型多任務在占先型多任務執行中處理器負責給每個線程分配一定量的運行時間??一個時間片(timeslice)處理器接著在不同的線程之間進行切換執行相應的處理在單處理器的計算機上並不能真正實現多個線程的同時運行除非運行在多個處理器的計算機上操作系統調度的多線程只是根據分配給每個線程時間片進行切換執行感覺上就像同時執行
上下文切換(context switching)是線程運行的一部分處理器使用一個硬件時間來判斷一個指定線程的時間片何時結束當這個硬件計時器給出中斷信號時處理器把當前運行的線程所用的所有寄存器(registers)數據存儲到堆棧中然後處理器把堆棧裡那些相同的寄存器信息存放到一種被稱為上下文結構的數據結構中
當處理器要切換回原來執行的線程時它反向執行這個過程利用與該線程相關的上下文結構在寄存器裡重新恢復與這一線程相關的信息這樣的一個完整過程稱為上下文切換
多線程允許應用程序把任務分割為多個線程它們彼此之間可以獨立地工作最大限度地利用了處理器時間
view plainprint?
using systemusing systemthreading
class simplethreadapp { public static void workerthreadmethod() //線程的執行體{…… //執行一些操作}
public static void main()
{ //創建一個線程代表指向線程的執行體threadstart是創建新線程必須用到的代表threadstart worker = new threadstart(workerthreadmethod)thread t = new thread(worker) //用線程代表創建線程tstart() //執行線程}可以通過兩種方式來得到一個thread對象一種是通過創建一個新線程來得到如上例另一種在正在執行的線程調用靜態的threadcurrentthread方法
靜態方法threadsleep(int ms)可以讓當前線程(它自動調用threadcurrentthread)暫停指定毫秒的時間
如果使用threadsleep()那麼當前線程將一直處於等待中直到另一個線程調用這個線程的實例方法threadinterrupt方法等待才會結束
使用threadsuspend方法也能掛起線程threadsuspend方法可以被當前線程或其他線程調用而threadsleep()
只能由當前線程在執行體中調用當線程用threadsuspend掛起時必須用threadresume方法恢復不論threadsuspend方法調用了多少次只要調用threadresume方法一次就可以線程恢復執行用threadsuspend方法並不會阻塞線程調用立即返回而threadsleep()則會阻塞線程所以確切地說threadsleep()暫停線程而不是掛起線程
> 使用threadabort方法可以終止正在執行的線程當threadabort方法被調用時線程不會立即終止執行運行環境將會等待直到線程到達文檔中所描述的安全點如果要確保線程已經完全停止可以使用threadjoin方法這是一個同步調用同步調用意味著直到線程完全停止調用才會返回
threadpriority屬性用於設置的線程的優先級其值是threadthreadpriority枚舉值可以設為highest abovenormalnormal belownormal lowest缺省值是threadthreadprioritynormal
線程的同步是為了解決多個線程同時使用同一對象產生的一些問題通過同步可以指定代碼的臨界區(critical section)一次只有一個線程可以進入臨界區
使用systemmonitor類(鎖定與信號量)進行線程同步
view plainprint?
using systemusing systemthreading
public void savedata(string text) //線程執行函數或線程執行函數調用的對象的方法{…… //執行其他一些不需要同步的處理
monitorenter(this) //獲取對象的monitor鎖…… //執行需要同步的處理monitorexit(this) //釋放對象的monitor鎖
…… //執行其他一些不需要同步的處理}說明當執行monitorenter方法時這個方法會試圖獲取對象上的monitor鎖如果另一個線程已經擁有了這個鎖這個方法將會阻塞(block)直到這個鎖被釋放
也可用c#的lock語句來獲得和釋放一個monitor鎖上面同步寫成
view plainprint?
public void savedata(string text) //線程執行函數或線程執行函數調用的對象的方法{…… //執行其他一些不需要同步的處理
lock(this) //獲取對象的monitor鎖代碼塊執行完成後釋放monitor鎖{…… //執行需要同步的處理}
…… //執行其他一些不需要同步的處理}也可以使用systemthreading名稱空間的mutex類(互斥類)進行線程同步與monitor鎖一樣一次只有一個線程能獲得一個給定的互斥但mutex要慢得多但它增加了靈活性例
view plainprint?
using systemusing systemthreading
class database { mutex mutex = new mutex(false) //創建一個互斥但不立即獲得它//注意創建互斥在需要同步的方法之外實際上它只要創建一個實例public void savedata(string text) //需要同步的方法{ mutexwaitone() //等待獲得互斥…… //需要同步的處理mntexclose() //釋放互斥} mutex類重載了三個構造函數mutex() //創建並使創建類立即獲得互斥mutex(bool initiallyowned) //創建時可指定是否要立即獲得互斥mutex(bool initiallyowned string mutername) //還可以指定互斥的名稱
mutexwaitone方法也重載了三次mutexwaitone() //一直等待mutexwaitone(timespan time bool exitcontext) //等待timespan指定的時間mutexwaitone(int milliseconds bool exitcontext) //等待指定的毫秒
線程的用法)並發操作比如一個程序監視多個com口當每個com接到信息時執行一段處理時
)復雜長時間操作一個長時間的復雜操作可能會使界面停滯停止用戶響應如果還允許用戶停止它或者顯示進度條顯示操作執行進程信息時
反射(reflection)就是能夠在運行時查找類型信息這是因為net編譯的可執行(pe)文件中包括msil和元數據(metadata)
反射的中心是類systemtypesystemtype是一個抽象類代表公用類型系統(common type system cts)中的一種類型
view plainprint?
using systemusing systemreflection //反射命名空間必須引用
public static void main(string[] args)
{ int i = type t = igettype() //根據實例得到類型t = typegettype(systemint) //根據類型的字符名稱得到類型}通過assembly類可以得到已經編譯net framework程序的中所有類型例
view plainprint?
using systemusing systemdiagnostics //為了使用process類using systemreflection //為了使用assembly類
class gettypesapp { protected static string getassemblyname(string[] args)
{ string assemblynameif ( == argslength) //如果參數為空取當前進程的名稱{ process p = processgetcurrentprocess()assemblyname = pprocessname + exe} else assemblyname = args[] //取第一個參數即當前運行程序名
return assemblyname}
public static void main(string[] args)
{ string assemblyname = getassemblyname(args)assembly a = assemblyloadfrom(assemblyname) //調用編譯程序集type[] types = agettypes() //得到多個類型foreach (type t in types) //遍歷類型數組{…… //取得tfullnametbasetypefullname等類型信息}一個應用程序可以包括多個代碼模塊若要將一個cs文件編譯一個模塊只要執行下面的命令csc /targetmodule 要編譯的模塊cs //csc是c sharp compiler(c#編譯器)
然後在應用程序中using編譯的模塊cs中的namespace即可應用了
要反射應用程序中所有代碼模塊(module)只要view plainprint?
assembly a = assemblyloadfrom(assemblyname) //應用程序的物理文件名module[] modules = agetmodules()foreach(module m in modules)
{…… //顯示mname等}後期綁定(latebinding)例
view plainprint?
string[] filenames = directorygetfiles(environmentcurrentdirectory *dll)foreach (string filename in filenames)
{ assembly a = assemblyloadfrom(filename)type[] types = agettypes()foreach(type t in types)
{ if (tissubclassof(typeof(commprotocol))) //判斷是否有commprotocol的派生類{ object o = activatorcreateinstance(t) //生成實例methodinfo mi = tgetmethod(displayname)miinvoke(o null) //調用方法} //帶參數的例子
view plainprint?
namespace programming_csharp { using systemusing systemreflection
public class tester { public static void main( )
{ type t = typegettype(systemmath)object o = activatorcreateinstance(t)
// 定義參數類型type[] paramtypes = new type[]paramtypes[]= typegettype(systemdouble)
methodinfo cosineinfo = tgetmethod(cos paramtypes)
//設置參數數據object[] parameters = new object[]parameters[] =
//執行方法object returnval = cosineinfoinvoke(o parameters)consolewriteline(the cosine of a degree angle {} returnval)}動態生成代碼和動態調用的完整例子//動態生成代碼的部分view plainprint?
using systemusing systemreflectionusing systemreflectionemit //動態生成代碼必須引用
namespace ilgenserver { public class codegenerator { public codegenerator()
{ currentdomain = appdomaincurrentdomain //得到當前域assemblyname = new assemblyname() //從域創建一個程序集assemblynamename = tempassembly//得到一個動態編譯生成器assemblybuileraccessrun表示只在內存中運行不能保存assemblybuilder = currentdomaindefinedynamicassembly(assemblyname assemblybuileraccessrun)//從編譯生成器得到一個模塊生成器modulebuilder = assemblybuilderdefinedynamicmodule(tempmodule)//模塊生成器得到類生成器typebuilder = modulebuilderdefinetype(tempclass typeattributespublic)//為類添加一個方法methodbuilder = typebuilderdefinemethod(helloword methodattributespublic null null)//為方法寫入代碼生成代碼必須使用到il生成器msil = methodbuildergetilgenerator()msilemitwriteline(hello world)msilemit(opcodesret)//最後還需要編譯(build)一下類t = typebuildercreatetype()}
appdomain currentdomainassemblyname assemblynameassemblybuilder assemblybuildermodulebuilder modulebuildertypebuilder typebuildermethodbuilder methodbuilderilgenerator msilobject otype tpublic type t { get { return thist} //動態調用的部分
view plainprint?
using systemusing systemreflectionusing ilgenserver //引用動態生成代碼的類
public class ilgenclientapp { public static void main({ codegenerator gen = new codegenerator() //創建動態生成類type t = gentif (null != t)
{ object o = activatorcreateinstance(t)methodinfo helloworld = tgetmethod(helloworld) //為調用方法創建一個methodinfo if (null != helloworld)
{ helloworldinvoke(o null) //調用方法}調用dll
view plainprint?
using systemusing systemruntimeinteropservices //為了使用dllimport特性
class pinvokeapp { [dllimport(userdll charset=charsetansi)] //charsetansi指定ansi版本的函數(messageboxa)charsetunicode指定unicode版本的函數(messageboxw)
static extern int messagebox(int hwnd string msg string caption int type) //聲明dll中的函數
//[dllimport(userdll entrypoint=messageboxa)] //用這種方法使用不同的函數名//static extern int msgbox(int hwnd string msg string caption int type)
//[dllimport(userdll charset=charsetunicode)] //調用unicode版的dll函數//static extern int messagebox(int hwnd [marshalas(unmanagedtypelpwstr)]string msg// [marshalas(unmanagedtypelpwstr)]string caption int type) //將lpwstr翻譯為string型缺省情況系統只將lpstr翻譯成string public static void main()
{ messagebox( hello world! captionstring ) //調用dll中的函數}例使用回調
view plainprint?
class callbackapp { [dllimport(userdll)] static extern int getwindowtext(int hwnd stringbuilder text int count)
delegate bool callbackdef(int hwnd int lparam)
[dllimport(userdll)] static extern int enumwindows(callbackdef callback int lparam)
static bool printwindow(int hwnd int lparam)
{ stringbuilder text = new stringbuilder()getwindowtext(hwnd text )consolewriteline(window caption {} text)return true}
static void main()
{ callbackdef callback = new callbackdef(printwindow)enumwindows(callback )}關鍵字unsafe指定標記塊在非控環境中運行該關鍵字可以用於所有的方法包括構造函數和屬性甚至還有方法中的代碼塊關鍵字fixed負責受控對象的固定(pinning)pinning是一種動作向垃圾收集器(garbage collector gc)指定一些不能被移動的對象為了不在內存中產生碎片net運行環境把對象四處移動以便於最有效地利用內存使用fixed後指定對象將不會被移動所以就可以用指針來訪問它
c#中只能得到值類型數組和字符串的指針在數組的情況下第一個元素必須是值類型因為c#實際上是返回一個指向數組第一個元素的指針而不是返回數組自身
& 取一個變量的內存地址(即指向該變量的指針)
* 取指針所指變量的值> 取成員例
view plainprint?
using system
class unsafeapp { public static unsafe void getvalues(int* x int* y)
{ *x = *y = }
public static unsafe void main()
{ int a = int b = getvalues(&a &b)} fixed語法為fixed(type* ptr = expression) statements其中type也可以為非控類型也可是voidexpression是任何產生一個type指針的表達式statements是應用的代碼塊例
view plainprint?
fixed (int* f = &foox) //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組件生成元數據包裝必須使用tlbimpexe(typelib importer)工具tlbimp some_comtlb /outsom_comdll
From:http://tw.wingwit.com/Article/program/net/201311/12010.html