目錄
一、程序的概念與作用
二、應用程式域
三、深入了解.NET上下文
四、程序應用程式域與線程的關系
使用.NET建立的可執行程式 *.exe,并沒有直接承載到程序當中,而是承載到應用程式域(AppDomain)當中。應用程式域是.NET引入的一個新概念,它比程序所占用的資源要少,可以被看作是一個輕量級的程序。
在一個程序中可以包含多個應用程式域,一個應用程式域可以裝載一個可執行程式(*.exe)或者多個程式集(*.dll)。這樣可以使應用程式域之間實作深度隔離,即使程序中的某個應用程式域出現錯誤,也不會影響其他應用程式域的正常運作。
當一個程式集同時被多個應用程式域調用時,會出現兩種情況:
第一種情況:CLR分别為不同的應用程式域加載此程式集。
第二種情況:CLR把此程式集加載到所有的應用程式域之外,并實作程式集共享,此情況比較特殊,被稱作為Domain Neutral。
2.1 AppDomain的屬性與方法
在System命名空間當中就存在AppDomain類,用管理應用程式域。下面是AppDomain類的常用屬性:
屬性 | 說明 |
ActivationContext | 擷取目前應用程式域的激活上下文。 |
ApplicationIdentity | 獲得應用程式域中的應用程式辨別。 |
BaseDirectory | 擷取基目錄。 |
CurrentDomain | 擷取目前 Thread 的目前應用程式域。 |
Id | 獲得一個整數,該整數唯一辨別程序中的應用程式域。 |
RelativeSearchPath | 擷取相對于基目錄的路徑,在此程式集沖突解決程式應探測專用程式集。 |
SetupInformation | 擷取此執行個體的應用程式域配置資訊。 |
表2.0
AppDomain類中有多個方法,可以用于建立一個新的應用程式域,或者執行應用程式域中的應用程式。
方法 | |
CreateDomain | 建立新的應用程式域。 |
CreateInstance | 建立在指定程式集中定義的指定類型的新執行個體。 |
CreateInstanceFrom | 建立在指定程式集檔案中定義的指定類型的新執行個體。 |
DoCallBack | 在另一個應用程式域中執行代碼,該應用程式域由指定的委托辨別。 |
ExecuteAssembly | 執行指定檔案中包含的程式集。 |
ExecuteAssemblyByName | 執行程式集。 |
GetAssemblies | 擷取已加載到此應用程式域的執行上下文中的程式集。 |
GetCurrentThreadId | 擷取目前線程辨別符。 |
GetData | 為指定名稱擷取存儲在目前應用程式域中的值。 |
IsDefaultAppDomain | 傳回一個值,訓示應用程式域是否是程序的預設應用程式域。 |
SetData | 為應用程式域屬性配置設定值。 |
Load | 将 Assembly 加載到此應用程式域中。 |
Unload | 解除安裝指定的應用程式域。 |
表2.1
AppDomain類中有多個事件,用于管理應用程式域生命周期中的不同部分。
事件 | |
AssemblyLoad | 在加載程式集時發生。 |
AssemblyResolve | 在對程式集的解析失敗時發生。 |
DomainUnload | 在即将解除安裝 AppDomain 時發生。 |
ProcessExit | 當預設應用程式域的父程序存在時發生。 |
ReflectionOnlyAssemblyResolve | 當程式集的解析在隻反射上下文中失敗時發生。 |
ResourceResolve | 當資源解析因資源不是程式集中的有效連結資源或嵌入資源而失敗時發生。 |
TypeResolve | 在對類型的解析失敗時發生。 |
UnhandledException | 當某個異常未被捕獲時出現。 |
表2.2
下面将舉例詳細介紹一下AppDomain的使用方式
2.2 在AppDomain中加載程式集
由表2.1中可以看到,通過CreateDomain方法可以建立一個新的應用程式域。
下面的例子将使用CreateDomain建立一個應用程式域,并使用Load方法加載程式集Model.dll。最後使用GetAssemblies方法,列舉此應用程式域中的所有程式集。
static void Main(string[] args)
{
var appDomain = AppDomain.CreateDomain("NewAppDomain");
appDomain.Load("Model");
foreach (var assembly in appDomain.GetAssemblies())
Console.WriteLine(string.Format("{0}\n----------------------------",
assembly.FullName));
Console.ReadKey();
}
運作結果
注意:當加載程式集後,就無法把它從AppDomain中解除安裝,隻能把整個AppDomain解除安裝。
當需要在AppDomain加載可執行程式時,可以使用ExecuteAssembly方法。
AppDomain.ExecuteAssembly("Example.exe");
2.3 解除安裝AppDomain
通過Unload可以解除安裝AppDomain,在AppDomain解除安裝時将會觸發DomainUnload事件。
下面的例子中,将會使用 CreateDomain建立一個名為NewAppDomain的應用程式域。然後建立AssemblyLoad的事件處理方法,在程式集加載時顯示程式 集的資訊。最後建立DomainUnload事件處理方法,在AppDomain解除安裝時顯示解除安裝資訊。
1 static void Main(string[] args)
2 {
3 //建立名為NewAppDomain的應用程式域
4 AppDomain newAppDomain = AppDomain.CreateDomain("NewAppDomain");
5 //建立AssemblyLoad事件處理方法
6 newAppDomain.AssemblyLoad +=
7 (obj, e) =>
8 {
9 Console.WriteLine(string.Format("{0} is loading!", e.LoadedAssembly.GetName()));
10 };
11 //建立DomainUnload事件處理方法
12 newAppDomain.DomainUnload +=
13 (obj, e) =>
14 {
15 Console.WriteLine("NewAppDomain Unload!");
16 };
17 //加載程式集
18 newAppDomain.Load("Model");
19 //模拟操作
20 for (int n = 0; n < 5; n++)
21 Console.WriteLine(" Do Work.......!");
22 //解除安裝AppDomain
23 AppDomain.Unload(newAppDomain);
24 Console.ReadKey();
25 }
namespace Test
{
public class Program
{
static void Main(string[] args)
{
var person=(Person)AppDomain.CurrentDomain
.CreateInstance("Model","Model.Person").Unwrap();
person.ID = 1;
person.Name = "Leslie";
person.Age = 29;
Console.WriteLine(string.Format("{0}'s age is {1}!",person.Name,person.Age));
Console.ReadKey();
}
}
}
namespace Model
{
public class Person
{
public int ID
{
get;
set;
}
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
}