這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)C#中AppDomain的作用是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

應(yīng)用程序域?yàn)榘踩浴⒖煽啃浴姹究刂埔约靶遁d程序集提供了隔離邊界。 應(yīng)用程序域通常由運(yùn)行時(shí)宿主創(chuàng)建,運(yùn)行時(shí)宿主負(fù)責(zé)在運(yùn)行應(yīng)用程序之前引導(dǎo)公共語(yǔ)言運(yùn)行時(shí)。
應(yīng)用程序域所提供的隔離具有以下優(yōu)點(diǎn):
(1)在一個(gè)應(yīng)用程序中出現(xiàn)的錯(cuò)誤不會(huì)影響其他應(yīng)用程序。 因?yàn)轭愋桶踩拇a不會(huì)導(dǎo)致內(nèi)存錯(cuò)誤,所以使用應(yīng)用程序域可以確保在一個(gè)域中運(yùn)行的代碼不會(huì)影響進(jìn)程中的其他應(yīng)用程序。
(2)能夠在不停止整個(gè)進(jìn)程的情況下停止單個(gè)應(yīng)用程序。 使用應(yīng)用程序域使您可以卸載在單個(gè)應(yīng)用程序中運(yùn)行的
注意:不能卸載單個(gè)程序集或類型。只能卸載整個(gè)域。
一切的根源,都是因?yàn)橹挥?Assembly.Load 方法,而沒(méi)有 Assembly.Unload 方法,只能卸載其所在的 AppDomain。
操作為讀取配置文件(為測(cè)試 AppDomain 中配置文件的讀取情況),并使用 Newtonsoft.Json 將其序列化為 json(為測(cè)試 AppDomain 中加載程序中的第三方引用情況),在控制臺(tái)輸出。項(xiàng)目名為 ReadPrint, 將其編譯為 exe 文件,并存放在 D:\AppDomainModules 中。
using Newtonsoft.Json;
using System;
using System.Configuration;
namespace ReadPrint
{
class Program
{
static void Main(string[] args)
{
DoSomething();
}
public static void DoSomething()
{
Person person = new Person
{
Account = ConfigurationManager.AppSettings["Account"],
Name = ConfigurationManager.AppSettings["Name"],
Age = int.Parse(ConfigurationManager.AppSettings["Age"])
};
Console.WriteLine(JsonConvert.SerializeObject(person));
Console.ReadLine();
}
class Person
{
public string Account { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
}為了查看方便定義了 DoSomething 來(lái)執(zhí)行相關(guān)方法。也可以直接寫(xiě)在 Main 方法中,調(diào)用時(shí)需要傳入?yún)?shù) args。因?yàn)樽罱K測(cè)試 AppDomain 的程序也打算使用控制臺(tái)應(yīng)用,也使用控制臺(tái)應(yīng)用來(lái)寫(xiě)這個(gè)小程序。
主要包含 AssemblyLoader.cs 文件用于封裝使用細(xì)節(jié),和 Program.cs 主程序文件。
AssemblyLoader.cs
using System;
using System.IO;
using System.Reflection;
namespace AppDomainTest
{
public class AssemblyDynamicLoader
{
private AppDomain appDomain;
public readonly RemoteLoader remoteLoader;
public AssemblyDynamicLoader()
{
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = "ApplicationLoader";
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
setup.CachePath = setup.ApplicationBase;
setup.ShadowCopyFiles = "true"; # 重點(diǎn)
setup.ShadowCopyDirectories = setup.ApplicationBase;
setup.ConfigurationFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules", "ReadPrint.exe.config");
//AppDomain.CurrentDomain.SetShadowCopyFiles();
this.appDomain = AppDomain.CreateDomain("ApplicationLoaderDomain", null, setup);
String name = Assembly.GetExecutingAssembly().GetName().FullName;
this.remoteLoader = (RemoteLoader)this.appDomain.CreateInstanceAndUnwrap(name, typeof(RemoteLoader).FullName); # 重點(diǎn)
}
public void Unload()
{
try
{
if (appDomain == null) return;
AppDomain.Unload(this.appDomain);
this.appDomain = null;
}
catch (CannotUnloadAppDomainException ex)
{
throw ex;
}
}
}
public class RemoteLoader : MarshalByRefObject
{
private Assembly _assembly;
public void LoadAssembly(string assemblyFile)
{
try
{
_assembly = Assembly.LoadFrom(assemblyFile);
}
catch (Exception ex)
{
throw ex;
}
}
public void ExecuteMothod(string typeName, string methodName)
{
if (_assembly == null)
{
return;
}
var type = _assembly.GetType(typeName);
type.GetMethod(methodName).Invoke(Activator.CreateInstance(type), new object[] { });
}
}
}其中類 RemoteLoader 為加載程序集的類,AssemblyDynamicLoader 類在此基礎(chǔ)上封裝了新建 AppDomain 的細(xì)節(jié)。
在 AssemblyDynamicLoader 的構(gòu)造函數(shù)中,為了測(cè)試方便,硬編碼了一些內(nèi)容,如 程序集文件查找路徑 PrivateBinPath 為當(dāng)前程序執(zhí)行目錄下面的 Modules 目錄,配置文件 ConfigurationFile 為 Modules 目錄中的 ReadPrint.exe.config, 以及創(chuàng)建新 AppDomain 時(shí)的程序集名稱。
AppDomainSetup 的屬性 ShadowCopyFiles(似乎可以譯為“卷影復(fù)制”) 代表是否鎖定讀取的程序集。如果設(shè)置為 true,則將程序集讀取至內(nèi)存,不鎖定其文件,這也是熱更新的前提;否則在程序執(zhí)行期間這些程序集文件會(huì)被鎖定,不能變化。
AppDomain 的方法 CreateInstanceAndUnwrap 意為在 AppDomain 的實(shí)例中創(chuàng)建指定類型的新實(shí)例,并返回。
在 RemoteLoader 的 ExecuteMethod 中,傳入的參數(shù)硬編碼為空。在實(shí)際使用時(shí)應(yīng)當(dāng)根據(jù)實(shí)際傳入?yún)?shù)。
Program.cs
using System;
using System.IO;
namespace AppDomainTest
{
class Program
{
static void Main(string[] args)
{
string modulesPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
DirectoryInfo di = new DirectoryInfo(modulesPath);
if (!di.Exists)
{
di.Create();
}
string remotePath = @"D:\AppDomainModules\";
string[] fileNames = new string[] { "ReadPrint.exe", "Newtonsoft.Json.dll", "ReadPrint.exe.config" };
foreach(var fileName in fileNames)
{
FileInfo fi = new FileInfo(Path.Combine(remotePath, fileName));
fi.CopyTo(Path.Combine(modulesPath, fileName), true);
}
AssemblyDynamicLoader adl = new AssemblyDynamicLoader();
adl.remoteLoader.LoadAssembly(Path.Combine(modulesPath, "ReadPrint.exe"));
adl.remoteLoader.ExecuteMethod("ReadPrint.Program", "DoSomething");
adl.Unload();
}
}
}在主程序文件中,創(chuàng)建 Modules 文件夾,拷貝程序文件、庫(kù)文件和配置文件。程序運(yùn)行結(jié)果:

可以看到成功調(diào)用了我們定義的 DoSomething 方法。
使用此方法,會(huì)首先在主程序的 AppDomain 中加載一遍程序集(和依賴),再移至我們創(chuàng)建的 AppDomain 中(特別注意,此時(shí)不會(huì)從我們新建的 AppDomain 的 PrivateBinPath 中搜索和加載)。
缺點(diǎn)有二,一是隨著程序的運(yùn)行,可能會(huì)加載大量的程序集,因此主程序的 AppDomain 也要加載大量程序集,而程序集無(wú)法單獨(dú)卸載,只有在主程序停止后才會(huì)卸載,其間必然越積越多,極不優(yōu)雅;二是無(wú)法自定目錄,主程序加載程序集和依賴時(shí)只會(huì)在其指定的 PrivateBinPath 中搜索,因此其它模塊所有需要的程序集文件都堆積在同一個(gè)目錄中,條理不清。
驗(yàn)證
修改 AssemblyDynamicLoader.cs 中的代碼,改為直接在構(gòu)造函數(shù)里面執(zhí)行程序加載,其它不變,并查看我們新建的 AppDomain 中已加載的程序集:
//String name = Assembly.GetExecutingAssembly().GetName().FullName;
//this.remoteLoader = (RemoteLoader)this.appDomain.CreateInstanceAndUnwrap(name, typeof(RemoteLoader).FullName);
Assembly assembly = this.appDomain.Load("ReadPrint");
Type t = assembly.GetType("ReadPrint.Program");
MethodInfo mi = t.GetMethod("DoSomething");
//mi.Invoke(Activator.CreateInstance(t), new object[] { });
var tmp = this.appDomain.GetAssemblies();此處最為奇怪的是,盡管我們?cè)谏厦嬷付俗约?AppDomain 的 PrivateBinPath 和 配置文件,執(zhí)行時(shí)依然找的是主程序的 PrivateBinPath 和 配置文件,因此將執(zhí)行的那一行代碼注釋。
修改 Program.cs 中的代碼,改為僅調(diào)用 AssemblyDynamicLoader 的構(gòu)造函數(shù),其它不變,并查看主程序 AppDomain 中已加載的程序集:
AssemblyDynamicLoader adl = new AssemblyDynamicLoader();
//adl.remoteLoader.LoadAssembly(Path.Combine(modulesPath, "ReadPrint.exe"));
//adl.remoteLoader.ExecuteMethod("ReadPrint.Program", "DoSomething");
//adl.Unload();
var tmp = AppDomain.CurrentDomain.GetAssemblies();
Console.ReadLine();結(jié)果如圖所示:


需要注意的是,RemoteLoader 類繼承了 MarshalByRefObject,而繼承此類的應(yīng)用可以跨 AppDomain 使用。此處猜測(cè)雖然可以在主程序中創(chuàng)建新的 AppDomain,但新的 AppDomain 依然無(wú)法完全擺脫主程序。
上述就是小編為大家分享的C#中AppDomain的作用是什么了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
當(dāng)前文章:C#中AppDomain的作用是什么-創(chuàng)新互聯(lián)
URL鏈接:http://chinadenli.net/article44/dgheee.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、服務(wù)器托管、品牌網(wǎng)站制作、外貿(mào)建站、網(wǎng)站導(dǎo)航、App開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容