我目前正在修改插件架构,以便它利用AppDomains。我的插件和我在网上找到的很多例子之间的主要区别在于,不是插件运行并将其结果发送回主应用程序,我的主应用程序是向插件发送信息的应用程序。
目前,我在一个单独的AppDomain中创建了一个加载器实例。然后它会执行所有正常的初始化,例如加载插件程序集。至此,我使用加载器的代理来调用将数据从主应用程序发送到新AppDomain的方法。
当我试图调用一个参数类型不可序列化且不是从MarshalByRefObject派生的方法时,会出现问题。
由于这些类型来自第三方代码,并且插件期望接收它们,我似乎找不到这样做的方法。在找到这个问题(How to solve "Must be MarshalByRefObject" in a good but multiple-inheritance amputated language like C#?)后,我正在考虑创建某种包装器。我的缺点是我无法找到一种方法来制作一个而不修改第三方代码。
以下是我的问题的一个例子:
// 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);
}
}
非常感谢任何帮助。
答案 0 :(得分:2)
如果这些只是跨越app域边界的实例,意味着你不要在多个app域中使用它们,你可以简单地将它们包装在一个派生自MarshalByRefObject的holder类中。
我在IronScheme的远程代码中使用了类似的方法。
问题是当你真正需要做的不仅仅是坚持实例时。在这种情况下,您可以使用接口来挂钩所需的方法,并通过'holder'类公开它。
答案 1 :(得分:1)
您是否需要让appdomain与第三方对象进行交互,并将其反映在另一方?如果没有(根据你的标题听起来你不会介意它们可序列化)那么为什么不序列化它们?我的意思是这样的:
[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);
}
}
当然,这种方法有一些警告,首先它依赖于你能够派生类,其次它需要你手动序列化数据(在一定程度上)。您可以使用内部字段上的反射来自动执行此操作,这实际上是您需要担心和重建的唯一方法,有效地手动序列化。
您可能已经能够实现代理选择器,但似乎没有向开发人员公开更改默认的应用程序间域名:(