CSharpScript使用外部定义类型时同类型转换失败问题求助
这个问题我太熟了!你猜的没错,就是程序集加载上下文不一致搞的鬼——你的主程序和CSharpScript各自加载了一份Common.dll,哪怕它们是同一个文件,CLR也会把这两个程序集里的Arguments和Output当成完全不同的类型,自然就转不过去了。
核心原因拆解
看错误信息里的两个Common.Arguments:一个带具体文件路径,一个是程序集版本标识,这说明主程序是在默认的程序集加载上下文中加载的Common.dll,而CSharpScript在自己独立的加载上下文里又重新加载了一遍。CLR判断类型是否相同的标准是程序集实例+类型全名,所以哪怕类型代码完全一样,来自不同程序集实例的类型就是不兼容的。
解决方案
方法1:复用主程序已加载的程序集(最简单)
修改脚本选项的构建代码,直接把主程序中已经加载的Common程序集实例传给脚本,而不是让脚本自己重新加载:
首先确保你的代码引用了System.Reflection命名空间,然后替换原来的AddReferences代码:
// 获取主程序中已加载的Common程序集实例 var commonAssembly = typeof(Arguments).Assembly; // 将这个实例添加到脚本选项中,让脚本复用它 options = options.AddReferences(commonAssembly);
这样脚本就会和主程序使用同一个程序集实例,类型自然就能匹配转换了。
方法2:用AssemblyLoadContext统一加载上下文(适配特殊场景)
如果方法1没生效(比如涉及到复杂的部署或插件场景),可以显式使用默认的AssemblyLoadContext来加载Common.dll,确保脚本和主程序处于同一个加载上下文:
先添加System.Runtime.Loader的引用,然后修改代码:
using System.Runtime.Loader; // 获取Common.dll的实际磁盘路径 var commonAssemblyPath = typeof(Arguments).Assembly.Location; // 用默认加载上下文加载程序集,避免脚本创建新的加载上下文 var commonAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(commonAssemblyPath); // 添加到脚本选项 options = options.AddReferences(commonAssembly);
额外优化建议
如果你的脚本逻辑不需要专门定义TestClass,可以直接把逻辑写成表达式,减少不必要的类型依赖:
// 直接创建返回Output的脚本,无需定义类 var script = CSharpScript.Create<Output>(@" return new Output() { Success = arguments.Text == text }; ", options: options, globalsType: typeof(Parameters)); // 运行后直接得到Output,无需强制转换 Output output = script.RunAsync(globals: parameters).Result.ReturnValue;
这样代码更简洁,还能避免脚本中定义类带来的额外类型匹配问题。
内容的提问来源于stack exchange,提问作者Daniel Wardin
相关产品推荐
相关产品推荐

