【问题标题】:Can .NET AppDomains do this?.NET AppDomains 可以做到这一点吗?
【发布时间】:2010-05-31 17:07:57
【问题描述】:

我花了几个小时阅读有关 AppDomain 的信息,但我不确定它们是否能像我希望的那样工作。

如果我有两个类,AppDomain #1 中的通用 Foo,AppDomain #2 中的 Bar:

App Domain #1 是应用程序。 App Domain #2 类似于插件,可以动态加载和卸载。

AppDomain #2 想要创建 Foo 并使用它。 Foo 在内部使用 AppDomain #1 中的许多类。

我不希望 AppDomain #2 使用带有反射的对象 foo,我希望它使用 Foo foo,并具有所有静态类型和编译速度。考虑到包含 Foo 的 AppDomain #1 永远不会被卸载,是否可以这样做?

如果是这样,使用 Foo 时是否在此处进行任何远程处理?

当我卸载 AppDomain #2 时,类型 Foo 被销毁?

编辑所以删除了我所有的,手动添加回来。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    您在问题中混合了类型和对象,因此很难回答。 AD 中的代码使用其他 AD 中也使用的类型没有问题,它只是加载程序集。但是一个 AD 有自己的垃圾收集堆,你不能直接引用另一个 AD 中的对象。它们需要跨 AD 边界进行序列化。是的,通过 IpcChannel 进行远程处理即可。

    【讨论】:

    • IpcChannel 不是必需的。您可以使用 appdomain.CreateInstance 为您执行此操作。只要有问题的类是可序列化的或 marshalobjbyref 的,您就可以获得所需的内容,而无需配置任何远程处理通道。 .net 运行时足够聪明,知道如何高效地在两个应用程序域之间进行远程处理,因为它们位于同一台计算机上。
    • 好的,如果我理解你,我可以创建 Foo; AppDomain #2 中的实例没有问题,可以正常使用它们 - 没有远程处理 - 只需加载包含 Foo 的程序集。我在 AppDomain #1 中真正需要的是分离出一个程序集,该程序集仅包含少数保存和管理我的非托管资源的静态长寿命单例,以便它们只有一个副本。这里不需要 Foo 。 AppDomain #2 中的 Foo 使用 AppDomain #1 中的这些对象的地方需要某种远程处理。跨 AppDomain 进行静态方法调用的某种方式 - 什么?
    • @Vagaus 似乎有答案,在 AppDomain #1 子类 MarshalByRefObject 中有对象,然后以来自 AppDomain #1 的长寿命单例的代理结束,这可以在 AppDomain 中愉快地使用#2,毫无疑问,跨 AppDomain 边界透明地编组方法参数和返回值。
    【解决方案2】:

    如果你想跨应用域访问对象,这些对象需要从 MarshalByRefObject 继承;在这种情况下,您最终将获得真实对象的代理。这样可以安全地卸载应用程序域(如果您尝试通过代理调用,则会引发异常)。

    我猜你想要完成的事情是这样的:

    using System;
    using System.Reflection;
    
    namespace TestAppDomain
    {
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain pluginsAppDomain = AppDomain.CreateDomain("Plugins");
    
            Foo foo = new Foo();
            pluginsAppDomain.SetData("Foo", foo);
    
            Bar bar= (Bar) pluginsAppDomain.CreateInstanceAndUnwrap(Assembly.GetEntryAssembly().FullName, typeof (Bar).FullName);
            bar.UseIt();
    
            AppDomain.Unload(pluginsAppDomain);
            foo.SaySomething();
        }
    }
    
    class Bar : MarshalByRefObject
    {
        public void UseIt()
        {
            Console.WriteLine("Current AppDomain: {0}", AppDomain.CurrentDomain.FriendlyName);
            Foo foo = (Foo) AppDomain.CurrentDomain.GetData("Foo");
            foo.SaySomething();
        }
    }
    
    class Foo : MarshalByRefObject
    {
        public void SaySomething()
        {
            Console.WriteLine("Something from AppDomain: {0}", AppDomain.CurrentDomain.FriendlyName);
        }
    }
    }
    

    如果您的类型是在不同的程序集中定义的(很可能),您可能会定义一个接口(在一个公共程序集中)并让这些类型实现该接口。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多