C# 動態類型與動態編譯簡介


關於C#的動態類型與動態編譯的簡介,主要是一個Demo。

動態類型

動態類型的應用場景

  1. 可以減少強制轉換(強制轉換其實挺好的,讓程序猿清楚地指定自己做了什么,不至於出錯時不知所措)
  2. 簡化反射的寫法。
  3. 與動態語言交互。
// Install-Package IronPython // 需要安裝此 Nuget包
// 引入動態類型之后
// 可以在C#語言中與動態語言進行交互
// 下面演示在C#中使用動態語言Python

ScriptEngine engine = Python.CreateEngine();

// 調用Python語言的print函數來輸出
engine.Execute("print 'Hello world'");

// 調用python求解漢羅塔問題
engine.Execute(PythonCode1());

// 調用python進行計算,返回 dynamic 類型
dynamic result = engine.Execute("123+456");

public static string PythonCode1()
{
    string code = "count=0\n" +
                    "def move(n,A,B,C):\n" +
                    "    global count\n" +
                    "    if(n==1):\n" +
                    "        print(A+\"->\"+C)\n" +
                    "        count = count + 1\n" +
                    "        return\n" +
                    "    move(n - 1, A, C, B)\n" +
                    "    move(1, A, B, C)\n" +
                    "    move(n - 1, B, A, C)\n" +
                    "    return\n" +
                    "move(5,\"A\",\"B\",\"C\")";
    return code;
}

動態編譯

javascript 和 matlab 等腳本語言會有 eval 這個函數,可以將一些動態生成的字符串作為代碼執行,某些情況下很實用。
C#同樣支持動態編譯。

最主要的兩個類:
CodeDomProviderCompilerParameters
前者相當於編譯器,后者相當於編譯器參數。

public static void Test1()
{
    CodeDomProvider compiler = new CSharpCodeProvider();     //編譯器
    CompilerParameters comPara = new CompilerParameters();   //編譯器參數

    comPara.GenerateExecutable = true; // 生成exe文件
    comPara.GenerateInMemory = false; // 是否在內存在輸出
    comPara.OutputAssembly = "SimpleCompile.exe"; // 輸出文件 

    compiler.CompileAssemblyFromSource(comPara, GetCode1());
    // 在當前目錄生成 SimpleCompile.exe ,可直接運行
}
public static string GetCode1()
{
    string code = @"using System;
            class Test
            {
                static void Main()
                {
                Console.WriteLine(""Hello world"");
                Console.ReadLine();
                }
            }";
    return code;
}

詳細下介紹可以看這里:

public static void Test2()
{
    CodeDomProvider compiler = new CSharpCodeProvider();     //編譯器
    CompilerParameters comPara = new CompilerParameters();   //編譯器參數

    comPara.GenerateExecutable = false;
    comPara.GenerateInMemory = true;

    // GetCode2() 見文末 
    CompilerResults compilerResults = compiler.CompileAssemblyFromSource(comPara, GetCode2());

    if (compilerResults.Errors.HasErrors)
    {
        Console.WriteLine("編譯錯誤");
        foreach (CompilerError err in compilerResults.Errors)
        {
            Console.WriteLine(err.ErrorText);
        }
        return;
    }

    // 通過反射,調用HelloWorld的實例
    Assembly objAssembly = compilerResults.CompiledAssembly;
    object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
    MethodInfo objMi = objHelloWorld?.GetType().GetMethod("OutPut");
    var result = objMi?.Invoke(objHelloWorld, null);

    Console.WriteLine(result);

    // 動態類型調用 
    // 可以看到,動態調用比反射調用寫法簡介不少  
    dynamic dynObj = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
    var result2 = dynObj?.OutPut();

    Console.WriteLine(result2);
}

CSScript

CSScript是C#的一個動態編譯引擎。
簡介看這里:

如果用原生的動態編譯,每次都要生成一個程序集,然后通過反射的方式去調用,過於麻煩。
如果只是想動態編譯一句代碼,CSScript提供了一種特別方便的寫法。

var sqr = CSScript.Evaluator
    .CreateDelegate(@"int Sqr(int a)
                        {
                            return a * a;
                        }");

var r = sqr(3); // 計算3的平方 

使用 CS-Script 需要安裝相關Nuget包 (會安裝很多東西,依賴項很多)

Install-Package CS-Script

  • Scripting.evaluator.cs
  • Scripting.Extensions.cs
  • Scripting.native.cs

這三個文件是 Nuget 安裝 CS-Script 之后自動載入的,里面有很多實用的例子~

有了CSScript,對原有的動態編譯的調用也變得簡單。

public static void Test1()
{
    // 得到 Assembly,反射調用
    Assembly ass = CSScript.LoadCode(GetCode2()); // GetCode2()見文末
    AsmHelper assAsmHelper = new AsmHelper(ass); 
    object obj = assAsmHelper.CreateObject("DynamicCodeGenerate.HelloWorld");
    var method = assAsmHelper.GetMethod(obj, "OutPut");
    object result = method.Invoke();

    // 動態調用
    dynamic obj2 = CSScript.Evaluator.LoadCode(GetCode2());
    dynamic result2 = obj2.OutPut();
}

關於CSScript的性能問題,可以參看這里:C#腳本引擎 CS-Script 之(二)——性能評測


public static string GetCode2()
{
    StringBuilder sb = new StringBuilder();
    sb.Append("using System;");
    sb.Append(Environment.NewLine);
    sb.Append("namespace DynamicCodeGenerate");
    sb.Append(Environment.NewLine);
    sb.Append("{");
    sb.Append(Environment.NewLine);
    sb.Append("    public class HelloWorld");
    sb.Append(Environment.NewLine);
    sb.Append("    {");
    sb.Append(Environment.NewLine);
    sb.Append("        public string OutPut()");
    sb.Append(Environment.NewLine);
    sb.Append("        {");
    sb.Append(Environment.NewLine);
    sb.Append("             return \"Hello world!\";");
    sb.Append(Environment.NewLine);
    sb.Append("        }");
    sb.Append(Environment.NewLine);
    sb.Append("    }");
    sb.Append(Environment.NewLine);
    sb.Append("}");

    string code = sb.ToString();

    return code;
}


免責聲明!

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



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