Application Domain可以看作是一個Assembly的邏輯容器在程序執行過程中如果遇到需要的Type並沒有定義在已經加載的Assemblies中 CLR會把相應的Assembly加載的該Application Domain中每個Application Domain都有一個屬於自己的加載器堆(Loader Heap)用於維護從Application Domain創建以後所用到的所有的Type以及這些Type對應的方法表——維護這樣一個Mapping定義在Type中的所有方法和經過JIT編譯後x代碼(只考慮bit處理器)
Application Domain之間是相互隔離互不干擾在一個Application Domain創建的對象不能被另一個Application Domain直接調用反映在內存分配上面——就是各個Application Domain使用各個獨立的內存地址空間一個對象根據他所對應的類型(如SystemMarshalByRefObject通過傳遞引用的方式)或者屬性(比如對於定義了System SerializableAttribute的Type采用傳遞值得方式)以兩種不同的方式在Application Domain之間傳遞——By Reference 和By Value
這些都是地球人都知道的NET的基本原理但是相信很多人沒有嘗試過通過Coding的方式證明這種機制
那麼現在我們就先來看看我們的Sample
下面是運行結果的Screen Shot
接下來我們來分析這段代碼
我們首先定義個個不同的Type他們都一個相同的方法——GetAppDomain()用於獲取執行該方法的真正的Application Domain
GeneralType一般的Type 沒有什麼特別
MarshalByValueType定義了一個System SerializableAttribute(你也可以通過使它實現 SystemRuntimeSerializationISerializable Interface來模擬這個Sample)它將以By Value的方式在不同的Application Domain之間傳遞
MarshalByRefType繼承自System MarshalByRefObject該類型的對象它將以By Reference的方式在不同的Application Domain之間傳遞
public class GeneralType
{
AppDomain GetAppDomain()
{
return AppDomainCurrentDomain;
}
}
[Serializable]
public class MarshalByValueType
{
public AppDomain GetAppDomain()
{
return AppDomainCurrentDomain;
}
}
public class MarshalByRefType : MarshalByRefObject
{
public AppDomain GetAppDomain()
{
return AppDomainCurrentDomain;
}
}
在Main()中我們首先創建一個新的Application Domain並為他指定一個Friendly Name——newAppDomain
AppDomain appDomain = AppDomainCreateDomain(newAppDomain)
接著我們分別在這個新建的Appliation Domain中創建我們在中定義的個類型的對象——generalObjectmarshalByValueObject marshalByRefObject並試著把它傳遞到當前的Application Domain——Default Application Domain從運行的結果我們可以看出當我們傳遞generalObject的時候一個Exception被拋出從Error Message可以開出原因——Type ArtechAppDomainIsolationGeneralType in assembly ArtechAppDomainIsolation Version= Culture=neutral PublicKeyToken=null is not marked as serializable從而我們可以看出一般的Type是不能在不同的Application之間傳遞的
通過證明了標記的System SerializableAttribute屬性和繼承自System MarshalByRefObject的Type對應的對象是可以在不同的Application Domain之間傳遞呢但是他們之間又會有怎樣的差異呢?他們是真正的對象呢?還僅僅是位於新建Application Domain中的對象一個代理(Proxy)?我們通過調用定義在SystemRuntimeRemoting中的靜態方法 IsTransparentProxy了解Remoting的人相信對這個方法不會感到陌生他用於判斷某個對象是否是一個Transparent Proxy(在當我們跨Application Domain遠程調用一個Remote Object的時候實際上我們並非直接調用Remote Object的方法而是通過一個同Client處在同一個Application Domain的Transparent Proxy對象間接地調用遠程對象——Transparent Proxy具有一個Remote Object的Reference可以輕易地找到這個Remote Object其實在真正的場景中Client調用Transparent ProxyTransparent Proxy再去調用Real ProxyReal Proxy最終才去調用Remote Object——如果你想進一步地了解Remoting你可以參照MSDN)
通過運行結果我們可以看到MarshalByValueType對象marshalByValueObject IsTransparentProxy方法返回False而對於MarshalByRefType對象marshalByRefObject則返回 True這就充分證明了標記了System SerializableAttribute屬性的Type所對應的對象是一個真正意義上的對象而對於繼承自MarshalByRefObject Type當該Type對應的對象從一個Application Domain傳遞到另一個Application Domain後另一個Application Domain獲得的僅僅是原來對象的Proxy而已
我們可以從傳遞的機制來解釋這種差異當你把System SerializableAttribute屬性運用要某個Type或者讓某個Class實現 SystemRuntimeSerializationISerializable Interface的時候你實際上是給該Type賦予了一種能力——一種可以序列化成XML的能力(XMLSerializer負責把對象序列化成 XML)當這種對象從一個Application Domain傳遞到另一個Application Domain的時候Object先被序列化成XML接著把XML傳遞到另一個Application Domain中在新的Application Domain中通過反序列化重新生成一個新的Object——這個新的Object和處於另一個Application Domain已經沒有任何關系
而對於而對於繼承自MarshalByRefObject Type的對象雖然他不能夠序列化成XML但是可以通過傳遞Reference的方式在Application Domain之間傳遞當這種傳遞實質上是通過在另一個Application創建一個擁有該對象引用的一個Proxy而這個Proxy依賴一這個處理另一個 Application Domain的真正對象
上面我們實際上已經說清楚了兩個對象傳遞的差異——By Value 和By Reference現在我們來進一步驗證前面我們說的我們繼續來看看我們的代碼
我們通過調用連個對象的GetAppDomain()方法從而獲得真正執行該方法的Application Domain然後再和當前的Application Domain進行比較我們發現對於MarshalByValueType對象marshalByValueObject真正執行操作是在當前的 Application Domain中進行的而對於MarshalByRefType對象marshalByRefObject則是我們新建立的Application Domain這充分證明了當marshalByValueObject傳遞到新的Application後生成一個和原來對象一模一樣的對象這個對象具有執行自身操作的能力而對於marshalByRefObject由於它只是一個Proxy而已他只有把對對象的操作請求發送給真正的位於另一個Application Domain的真正對象(同時他也負責把遠程對象的執行結果返回給調用者)真正的操作實際上是發生在遠程對象的Application Domain
由於marshalByRefObject依賴於遠程對象所以當我們卸載掉Host遠程對象的Application Domain對marshalByRefObject的任何調用將變得無效所以這裡可以對下面這段代碼作出解釋
注在分布式開發中我們會大量接觸到By Value 和By Refernce傳遞一般而言By Value用於商業實體的傳遞(Business Entity)而By Reference用於遠程調用(RPC)或者是調用Service
From:http://tw.wingwit.com/Article/program/ASP/201311/21677.html