使用 IDisposable 时卸载 AppDomain [英] Unload an AppDomain while using IDisposable

查看:27
本文介绍了使用 IDisposable 时卸载 AppDomain的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含工厂方法的可编组类.工厂方法可用于实例化测试 AppDomain 中的类.我试图了解我是否可以将类与 using( ... ) 处理模式一起使用.

I have a marshalable class that contains a factory method. The factory method can be used to instantiate the class in a test AppDomain. I'm trying to understand whether I can use the class with the using( ... ) dispose pattern.

我最关心的是测试 AppDomain 是否已卸载——以及何时卸载.我在调用实例方法时设置的类中添加了一个静态标志.如果 appdomain 没有卸载,那么我相信这个标志应该在后续调用中保留它的设置.

The principle concern for me is whether the test AppDomain is Unloaded -- and when. I've added a static flag to the class that's set when an instance method is invoked. If the appdomain is not unloaded, then I believe this flag should retain it's setting in subsequent invocations.

示例类和测试控制台应用程序如下所示:

A sample class and test console app would look like this:

using System;
using System.Reflection;
using System.Threading;

namespace AppDomainInDispose
{
    public class TestClass : MarshalByRefObject, IDisposable
    {
        public void Run()
        {
            Console.WriteLine("Hello from {0}", Thread.GetDomain().FriendlyName);
            if (_flag)
                Console.WriteLine("Flagged!");
            else
                _flag = true;
        }

        private static bool _flag = false;

        public static TestClass InstantiateInTestDomain()
        {
            var callingDomain = Thread.GetDomain();
            var setup = new AppDomainSetup() { ApplicationBase = callingDomain.SetupInformation.ApplicationBase };
            _domain = AppDomain.CreateDomain("test-domain", null, setup);
            _domain.DomainUnload += _domain_DomainUnload;

            var assembly = Assembly.GetAssembly(typeof(TestClass)).CodeBase;
            var proxy = _domain.CreateInstanceFromAndUnwrap(assembly, "AppDomainInDispose.TestClass") as TestClass;

            return proxy;
        }

        static void _domain_DomainUnload(object sender, EventArgs e)
        {
            Console.WriteLine("Unloading");
        }

        public static AppDomain _domain = null;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~TestClass()
        {
            Dispose(false);
        }

        private void Dispose(bool disposing)
        {
            if(disposing)
            {
                //AppDomain.Unload(_domain);    // can't, as I'm in the AppDomain
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using(var testClass = TestClass.InstantiateInTestDomain())
            {
                testClass.Run();
            }
            using (var testClass = TestClass.InstantiateInTestDomain())
            {
                testClass.Run();    // if the appdomain hasn't been unloaded then the static flag will still be set
            }

            Console.ReadKey();
        }
    }
}

似乎在这个有限的测试中,AppDomain 正在被卸载——但我不确定在哪里.有人可以解释一下 AppDomain 发生了什么吗?这种方法是不是一个很糟糕的主意?

It seems that in this limited test the AppDomain is being unloaded -- but I'm not sure where. Could someone explain what's going on with the AppDomain? Is this approach a very bad idea?

看起来您可以让多个 AppDomains 共享相同的名称,这是我没有意识到的.此外,不会触发 DomainUnload 事件,因此我可能假设该域没有被卸载.或者在某些情况下(可能在托管进程关闭时)不会触发事件.

Looks like you can have multiple AppDomains sharing the same name, which I didn't realise. Also, the DomainUnload event isn't fired, so I might assume that the domain is not being unloaded. That, or the event is not fired in some circumstances (perhaps while the hosting process is shutting down).

推荐答案

嗯.. 有点复杂了.如果您想确保在 using 块结束后应用域确实被卸载,下面是一个这样的实现.我在这里分离了两个问题创建应用程序域和应用程序域的处理"和正在应用程序域中加载的类型本身".(所有这些都在主编类中)

Hmmm.. it is getting a bit complicated. If you want to be sure that the app domain does get unloaded after the using block end, below is one such implementation. I have separated the 2 concerns here "create app domain and handling of app domain" and "the Type itself that is being loaded in app domain". (All this is in main prog class)

public class GenericDisposable<T> : IDisposable
{
    public Action Dispose { get; set; }
    public T Object { get; set; }
    void IDisposable.Dispose()
    {
        Dispose();
    }

}
public static GenericDisposable<T> CreateDomainWithType<T>()
{
    var appDomain = AppDomain.CreateDomain("test-domain");
    var inst = appDomain.CreateInstanceAndUnwrap(typeof(T).Assembly.FullName, typeof(T).FullName);
    appDomain.DomainUnload += (a, b) => Console.WriteLine("Unloaded");
    return new GenericDisposable<T>() { Dispose = () => AppDomain.Unload(appDomain), Object = (T)inst };
}
public class User : MarshalByRefObject
{
    public void Sayhello()
    {
        Console.WriteLine("Hello from User");
    }
}

//Usage              
static void Main()
{
    using (var wrap = CreateDomainWithType<User>())
    {
        wrap.Object.Sayhello();
    }
    Console.Read();
}

这篇关于使用 IDisposable 时卸载 AppDomain的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆