我會創建一個單獨的應用程序域來運行一個不受信任的程序集,或者就像你的情況那樣不時工作。應用程序域可以隨時卸載,它將在您的代碼和外部代碼之間創建一個邊界。這是一個小例子。讓我們先從包含不正確的代碼外部組件:
public class Processor
{
public void Run()
{
while (true) { /* ... */ }
}
}
現在,我們需要一個類,將加載BadAssembly.dll,創建處理器的一個實例,並調用運行方法在單獨的線程中爲了不阻止你的應用程序的主線程。
public class Loader : MarshalByRefObject
{
public bool IsCompleted { get; private set; }
public bool IsFaulted { get; private set; }
public void LoadAndRunBadAssembly()
{
var ass = Assembly.LoadFrom("BadAssembly.dll");
var c = (Processor)ass.CreateInstance("BadAssembly.Processor");
Task.Factory.StartNew(() =>
{
try
{
c.Run();
IsCompleted = true;
}
catch (Exception)
{
IsFaulted = true;
}
}, TaskCreationOptions.LongRunning);
}
}
IsCompleted和IsFaulted性需要,讓我們知道,如果外部的代碼已經處理完畢或沒有。 加載程序從MarshalByRefObject派生,因爲它的代碼將在我們創建的獨立域中執行。這裏是一個代碼來測試裝載機類:
var appDomain = AppDomain.CreateDomain("Loader");
try
{
//Here I assume that Loader class is in the same assembly as this code
var loader = (Loader)appDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof (Loader).FullName);
loader.LoadAndRunBadAssembly();
Console.WriteLine("Waiting...");
Thread.Sleep(20000); //This simulates waiting for external code
if (loader.IsCompleted)
Console.WriteLine("Processing has finished");
else if (loader.IsFaulted)
Console.WriteLine("There was an error");
else
Console.WriteLine("It lasts too long");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
AppDomain.Unload(appDomain);
}
UPDATE
我剛剛意識到,爲了停止線程在一個域中AppDomain.Unload方法使用中止方法。這意味着您在嘗試卸載域時可能會收到CannotUnloadAppDomainException異常。它會發生,因爲不能保證中止會立即殺死一個線程。
你如何從這個庫調用代碼?你是否明確地創建了一個新的線程,如果是的話,怎麼樣?一段代碼將會很有用。 – 2014-11-08 14:30:35
這是不可能的,只是殺死線程。唯一可以安全殺死的就是整個過程。 '線程。Abort'只會在線程執行託管代碼時工作,所以對於本地的第三方庫來說,這無濟於事。因此,將違規代碼分離成一個新的簡單流程,您可以從您的應用程序運行並在需要時終止。 – Luaan 2014-11-08 15:09:18