目录

一、进程的概念与作用

二、应用程序域

三、深入了解.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 }

运行结果

 

2.4 在AppDomain中建立程序集中指定类的对象

使用CreateInstance方法,能建立程序集中指定类的对像。但使用此方法将返回一个ObjectHandle对象,若要将此值转化为原类型,可调用Unwrap方法。
下面例子会建立Model.dll程序集中的Model.Person对象。

 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;
           }
      }
 }