1.C#层:利用.NET framework的CodeDom或Mono的Evaluator动态编译解释CS脚本
2.IL层:利用System.Reflection.Emit或Mono.Cecil动态生成IL指令并执行
3.造轮子自己实现IL解释器(取代.NET或Mono的IL解释器,这种方案可以绕过苹果实现热更新)
4.直接调用Mono的编译器进行编译生成dll,例如Win平台"..Monoingmcs.bat"
参考:
- Clearscript、paxScript.NET
-
Dynamically executing code in .Net (比较不错,他还提供了个wwScripting,方便使用,还支持将代码加载到新的AppDomain)
CodeDom:
经过最新研究,这玩意其实就是去调用gmcs来生成代码的,跟直接用gmcs没差,在Unity编辑器里可以直接用,但打包出来就不行了,因为认不出gmcs的路径
微软链接:https://msdn.microsoft.com/en-us/library/saf5ce06(v=vs.110).aspx
不生成程序,直接写在内存并调用生成的内容:http://stackoverflow.com/questions/24871955/c-sharp-compilerresults-generateinmemory
1.动态编译CS代码
作者:知乎用户 链接:https://www.zhihu.com/question/31230641/answer/51098145 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 using System; using System.Collections.Generic; using System.Linq; using Microsoft.CSharp; using System.CodeDom.Compiler; class Program { static void Main(string[] args) { var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } }); var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true); // 生成exe,若为false,则生成dll parameters.GenerateExecutable = true; CompilerResults results = csc.CompileAssemblyFromSource(parameters, @"using System.Linq; class Program { public static void Main(string[] args) { var q = from i in Enumerable.Range(1,100) where i % 2 == 0 select i; } }"); results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText)); } }
这种方法方便,强大,但缺点是不支持打包后的版本(不管是PC还是安卓,毕竟在Editor里有集成msc,打包后没有),即使你将Unity的PlayerSetting里的Api Compatibitility Level设置为.NET 2.0也没办法,顶多是加入了namespace的引用,能在代码里调用和编译通过而已,但实际运行起来,还是会报错:
官方论坛里有人遇到同样的错误:http://answers.unity3d.com/questions/309490/is-it-possible-to-compile-and-run-c-code-on-the-fl.html
据说Xamarin支持?没试过:https://developer.xamarin.com/api/namespace/System.CodeDom/
Evaluator:
这玩意其实不错,但由于Unity目前只支持到.net 3.5,而3.5版的Mono.CSharp的Evaluator又比较烂,不支持类跟函数,只能解析简单的语句
- 小试牛刀C#作为脚本语言执行解密
- https://forum.unity3d.com/threads/mono-csharp-evaluator.102162/
- http://answers.unity3d.com/questions/309490/is-it-possible-to-compile-and-run-c-code-on-the-fl.html
public class Data { public static int n = 0; public static GameObject go = null; } Mono.CSharp.Evaluator.Init(new string[] {} ); Assembly a = Assembly.GetExecutingAssembly(); Mono.CSharp.Evaluator.ReferenceAssembly(a); Mono.CSharp.Evaluator.Run("Data.n=Data.n+5;"); Debug.Log(Data.n); //5
支持在PC跟安卓上,IOS不行
调用Mono编译器动态编译:
CodeDom是比较完美的解决方案,无奈打包后的程序里的mono只包含runtime部分,没有编译部分工具,所以会导致打包后运行失败,
所以Github(mcs-ICodeCompiler)上已经有大佬将mono里的msc部分单纯提取出来,编译成一个dll,供项目调用。
原理很简单,CodeDom不是需要msc么?直接将所需的程序集部分提供给它就行,这部分很小,近1M左右,如果是整个mono项目,那非常巨大,估计几十M。
注意:这种方法需要你的Unity项目必须是.NET 2.0,而不是.NET 2.0 Sub,如果是sub也所谓,直接将完整版的.NET 2.0里的System.dll替换进来即可。
注意2:CodeDom目前有个BUG,就是不支持Enum,若使用会使程序崩溃: https://bugzilla.xamarin.com/show_bug.cgi?id=24607