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平台"..\Mono\bin\gmcs.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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM