13

我正在尝试将来自不同程序集(在构建时未知)的类型加载为“动态”并在该类型上执行方法。我的目标是完全断开“插件”与父应用程序的连接,这样就不需要任何共享代码或通用接口类型。该接口通过加载类型上的预期方法签名来暗示。

这有效:

dynamic myObj = Assembly.Load("MyAssembly").CreateInstance("MyType");
myObj.Execute();

但是,这会将类型及其所有相关程序集加载到当前 AppDomain 中。我想修改它以允许我在单独的 AppDomain 中做同样的事情。

这有效,但不使用 dynamic 关键字,我需要知道我正在实例化的显式类型才能调用 Execute 方法:

var appDomain = AppDomain.CreateDomain(domainName, evidence, setup);
var myObj = appDomain.CreateInstanceAndUnwrap(assembly, type);
typeof(IMyInterface).InvokeMember("Execute",  BindingFlags.InvokeMethod, null, myObj);

这基本上是我的目标案例,我一直试图让这样的事情起作用:

dynamic myObj = ad.CreateInstanceAndUnwrap(assembly, type);
myObj.Execute();

我一直以带有消息“'System.MarshalByRefObject'不包含'Execute'的定义”的RuntimeBinderException结束。这条消息是有道理的,确保它不包含“执行”的定义,但我知道我正在实例化的类型确实包含一个“执行”方法。我想透明代理在这里发生了一些事情,阻止了它的工作,但我不确定是什么。

我试图实例化的实际类如下所示:

[Serializable]
public class MyClass : MarshalByRefObject {
  public void Execute() {
    // do something
  }
}

我也尝试过使用共享界面(不是我的主要目标,但我试图先解决这个问题),所以它看起来像:

[Serializable]
public class MyClass : MarshalByRefObject, IPlugin {
  public void Execute() {
    // do something
  }
}

其中 IPlugin 是父应用程序中的已知类型,并且插件在构建时具有适当的引用,但这似乎也不起作用。

我猜在这一点上,不可能在 AppDomain 边界上将类型加载为动态。

有没有办法让它真正发挥作用?

4

1 回答 1

5

正如leppie 指出的那样,您必须实现IDynamicMetaObjectProvider接口来包装返回给您的代理,然后您可以在其上使用makedynamic调用。

在您的实现中,您希望采用包装的代理并将所有调用转发到class上的静态ExecuteMessage方法,这将采用您的代理以及接口实现。RemotingServicesIMethodCallMessage

请注意,实现IMethodCallMessage接口并非易事。此外,您必须正确解释IMethodReturnMessage接口实现以正确获取返回值refout参数(如果有)。

也就是说,提供一个包含一个供客户端和服务器假设的接口的程序集通常是一个更好的主意。如果在服务器端以任何方式更改方法,即使客户端使用dynamic,您仍然必须更改调用站点以适应更改。至少使用该接口,您可以获得某种类型的编译时检查,这总是比运行时错误更受欢迎。

于 2012-06-26T20:34:14.473 回答