我有一个应用程序,我在其中使用 CSharpCodeProvider 允许通过 C# 代码进行集成脚本。脚本可以引用动态发出的程序集(这些是通过 IL Emit 创建的);为了允许这个引用,我将动态生成的程序集保存到磁盘上的一个文件中,然后将此位置添加到 CompilerParameters.ReferencedAssemblies 集合中。
这适用于脚本的第一次编译和执行。我有实例化从脚本生成的类的代码,该类有一个带参数的构造函数,其中一些是来自动态发出的程序集的类型。它看起来像这样:
var hostType = _compilerResults.CompiledAssembly.GetType("ExMod.Engine.ScriptHost");
var parameters = new List<object>();
parameters.Add(simulation);
var extraParameters =
simulation.Environment.Controllers.
Select(c => c.GetPrecompiledContext()).
Where(c => c != null);
parameters.AddRange(extraParameters);
_scriptHost = (ScriptHostBase)Activator.CreateInstance(hostType, parameters.ToArray());
extraParameters 表达式是添加对外部动态生成类型的引用的地方。
当我再次尝试编译和运行脚本时,就会出现问题。仅当我还重新发出了新版本的 IL Emit 程序集时才会发生这种情况。异常发生在 Activator.CreateInstance 调用上,并且是:
MissingMethodException: Constructor on type 'ExMod.Engine.ScriptHost' not found.
观察:
- 我已经通过调试器确认存在具有正确参数的构造函数。
- 我还确认(使用调试器中的 Make Object ID)导致问题的原因是构造函数中的“Controller”参数(来自动态发出的程序集的引用类型)指的是原始动态程序集,而不是最最近发出的动态程序集,这就是类型不匹配且构造函数无法解析的原因。
- 当我运行 CSharpCodeProvider 编译器然后尝试运行脚本时,它从不调用我的 AppDomain AssemblyResolve 事件,这是我有特殊逻辑始终解析为“最新”动态程序集的地方。
我的理论是,CSharpCodeProvider 以某种方式解决了“最早的”动态程序集,而不是“最新的”。发生这种情况是因为它们都具有相同的名称和位置。问题:如何让 CSharpCodeProvider 解析为最新版本的动态程序集?
我考虑过更改每个动态发出的程序集的位置,但我不希望为每个脚本迭代在磁盘上创建一堆副本。