C# 动态编译

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"

参考:

  1. C#动态创建和动态使用程序集、类、方法、字段等

  2. Emit动态生成代码

  3. Unity3d跨平台原理

  4. 动态生成与编译(一)----入门

  5. C#脚本引擎 CS-Script 之(一)——初识

  6. IL解释器:ILRuntimeL#ApolloClr

  7. ClearscriptpaxScript.NET
  8. Compile C# at runtime in Unity3D

  9. Dynamically executing code in .Net (比较不错,他还提供了个wwScripting,方便使用,还支持将代码加载到新的AppDomain)

  10. C#Light/Evil 是一组pure C#写成的脚本语言

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又比较烂,不支持类跟函数,只能解析简单的语句

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

原文地址:https://www.cnblogs.com/jeason1997/p/6675694.html