我正在尝试将来自不同程序集(在构建时不知道)的类型加载为“动态”并在该类型上执行方法。我的目标是完全断开'插件'与父应用程序的连接,这样就不需要任何共享代码或通用接口类型。通过加载类型上的预期方法签名来暗示接口。
这有效:
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();
我一直以RuntimeBinderException结尾,消息“'System.MarshalByRefObject'不包含'Execute'的定义”。这条消息有意义,确定它不包含'Execute'的定义,但我知道我实例化的类型确实包含'Execute'方法。我想这里有一些透明代理正在阻止它工作,但我不确定是什么。
我尝试实例化的实际课程如下:
[Serializable]
public class MyClass : MarshalByRefObject {
public void Execute() {
// do something
}
}
我也尝试过这个共享界面(不是我的主要目标,但我想先弄清楚这个)所以它看起来像:
[Serializable]
public class MyClass : MarshalByRefObject, IPlugin {
public void Execute() {
// do something
}
}
其中IPlugin是父应用程序中的已知类型,并且插件在构建时具有适当的引用,但这似乎也不起作用。
我猜在这一点上,不可能在AppDomain边界上加载一个动态类型。
有没有办法让它真正起作用?
答案 0 :(得分:5)
作为leppie indicated,您必须实施IDynamicMetaObjectProvider
interface以包装要返回给您的代理,然后您可以使用make dynamic
来电在那。
在您的实施中,您希望获取已包装的代理并将所有调用转发到ExecuteMessage
method上的静态RemotingServices
class,这将占用您的代理,以及{{{ 3}}实施。
请注意,实现IMethodCallMessage
接口并非易事。此外,您必须正确解释IMethodCallMessage
interface实施,以正确获取返回值,ref
和out
参数(如果有)。
也就是说,提供一个仅包含 接口的程序集通常是一个更好的主意,供客户端和服务器承担;如果在服务器端以任何方式更改方法,即使客户端使用dynamic
,您仍然 仍需要更改呼叫站点以适应更改。至少使用接口,您可以获得某种类型的编译时检查,这始终是运行时错误的首选。