[英]CSharpCodeProvider and resolution of dynamic assemblies
我有一个应用程序,使用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.
观察结果:
我的理论是CSharpCodeProvider以某种方式正在解决“最早的”动态程序集而不是“最新的”程序集。 发生这种情况是因为它们具有相同的名称和位置。 问题:如何使CSharpCodeProvider解析为动态程序集的最新版本?
我已经考虑过更改每个动态发出的程序集的位置,但是我不希望为每次脚本迭代在磁盘上创建一堆副本。
我发现我可以通过使发射代码为每个版本创建一个新的版本号来解决此问题。 我只是在生成AssemblyName的代码中使用此代码:
var name = new AssemblyName();
name.Name = "AB-PLC";
name.Version = new Version(0, 0, Interlocked.Increment(ref _buildNumber), 0);
上面的_buildNumber是一个简单的静态int字段。
这使得CSharpCodeProvider可以解析正确的程序集,因为现在不同版本的FullName不再匹配。 我仍然只有一个程序集副本导出到磁盘(被每个IL Emit版本覆盖。)
我仍然很想知道是否可以允许CSharpCodeProvider在不更改其FullName的情况下解析正确的程序集,但是此解决方案目前足以满足我的目的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.