3

我目前正在修改插件架构,以便它利用 AppDomains。我的插件与我在网上找到的许多示例之间的主要区别在于,不是插件运行并将其结果发送回主应用程序,而是我的主应用程序是向插件发送信息的一个。

就目前而言,我在单独的 AppDomain 中创建了加载程序的实例。然后它会执行所有正常初始化,例如加载插件程序集。至此,我然后使用加载器的代理来调用将数据从主应用程序发送到新 AppDomain 的方法。

当我尝试调用具有不可序列化的参数类型且不是从 MarshalByRefObject 派生的方法时,就会出现我的问题。

由于这些类型来自 3rd 方代码,并且插件希望接收它们,因此我似乎找不到这样做的方法。在找到这个问题(如何用像 C# 这样的良好但多继承截断语言解决“必须是 MarshalByRefObject”?)后,我正在考虑创建某种包装器。我的缺点是我根本无法找到一种方法来制作一个不修改第 3 方代码的方法。

这是我的问题的一个例子:

// Cant modify this class
class ThirdPartyClass
{
    // The properties are also 3rd party and nonserializable. These are accessed by the plugins.
    public AnotherClass Property1{ get; set; }
    public AnotherClass Property2{ get; set; }

    public ThirdPartyClass(){}
}

class Loader : MarshalByRefObject
{
    private Plugin plugin;

    public Loader()
    {
        Assembly pluginAssembly = Assembly.LoadFrom("Full/Assembly/Path");
        plugin = pluginAssembly.CreateInstance("Full.Plugin.Name") as Plugin;
    }

    public void DoSomething(ThirdPartyClass o)
    {
        ...
        plugin.DoSomethingElse(o);
    }
}

class PluginManager
{
    void Main(ThirdPartyClass o)
    {
        AppDomain pluginAppDomain = AppDomain.CreateDomain("Plugin AppDomain");
        Loader loader = pluginAppDomain.CreateInstanceFromAndUnwrap("Full/Loader/Path", "Full.Loader.Name") as Loader;

        // This is where I would have a problem.
        loader.DoSomething(o);
    }
}

任何帮助将不胜感激。

4

2 回答 2

2

如果这些只是跨越应用程序域边界的实例,这意味着您不会在多个应用程序域中使用它们,您可以简单地将它们包装在从 MarshalByRefObject 派生的持有者类中。

我在 IronScheme 的远程处理代码中使用了类似的方法。

问题是当您实际上需要做的不仅仅是保持实例时。在这种情况下,您可能可以使用接口来挂钩所需的方法并通过“持有人”类公开它。

于 2012-06-28T17:37:27.050 回答
1

您是否需要让 appdomain 与第 3 方对象交互并反射回另一方?如果不是(并且根据您的标题,听起来您不介意它们是可序列化的)那么为什么不序列化它们呢?我的意思是类似于:

[Serializable]
class MyThirdPartyClass : ThirdPartyClass, ISerializable
{
    public MyThirdPartyClass()
    {
    }

    protected MyThirdPartyClass(SerializationInfo info, StreamingContext context)
    {
        Property1 = (AnotherClass)info.GetValue("Property1", typeof(AnotherClass));
        Property2 = (AnotherClass)info.GetValue("Property2", typeof(AnotherClass));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Property1", Property1);
        info.AddValue("Property2", Property2);
    }
}

当然,这种方法有一些注意事项,首先它依赖于您能够派生类,其次它需要您手动序列化数据(在一定程度上)。您可以使用内部字段上的反射来自动执行该操作,这实际上是您唯一需要担心和重建的事情,有效地手动序列化。

您可能已经能够实现一个代理选择器,但它似乎没有暴露给开发人员来更改默认的跨应用程序域之一:(

于 2012-06-28T21:00:44.363 回答