首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

打造輕量級 C# Shell:OrcShell 類型瀏覽與動態代碼執行實作

     編輯:關於.NET

OrcShell 是一個實驗性的 C# 互動式殼層,支援類型瀏覽、命名空間導航、成員檢視與動態代碼片段編譯執行。本文深入剖析其核心模組實作細節,展示如何利用反射與 CSharpCodeProvider 建構動態執行環境。

一、類型管理架構

1. 程序集與類型載入

Context 初始化時掃描當前 AppDomain 所有已載入程序集,並透過 TypeManager 統一管理類型資訊。程式碼會過濾掉編譯器生成的 <PrivateImplementationDetails> 內部類型:

public Context() {
    TypeManager = new TypeManager();
    Assemblys = new Dictionary<String, Assembly>();
    Assembly[] al = AppDomain.CurrentDomain.GetAssemblies();
    foreach (Assembly a in al) { AddAssembly(a); }
    AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
}

private void AddAssembly(Assembly a) {
    if (a != null) {
        Assemblys.Add(a.FullName, a);
        Type[] tl = a.GetTypes();
        foreach (Type t in tl) {
            if (!t.FullName.StartsWith("<PrivateImplementationDetails>"))
                TypeManager.AddType(t);
        }
    }
}

void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) {
    Assembly a = args.LoadedAssembly;
    if (!Assemblys.ContainsKey(a.FullName)) AddAssembly(a);
}

2. 命名空間導航 (CdClassCmdHandler)

支援相對/絕對路徑切換(cdc ..、cdc .、cdc NamespaceName),不支援級聯(cdc ../ns1/ns2)。輸入部分名稱時自動比對,唯一匹配則直接進入,否則列出所有匹配項。

3. 列出命名空間與類型 (ListClassCmdHandler)

支援正則表達式過濾,由 TypeDictionary 實作列舉邏輯:

public void ListType(String match) {
    Regex re = match != null ? new Regex(match) : null;
    foreach (Type t in Types.Values) {
        if (re != null && !re.IsMatch(t.Name)) continue;
        Console.WriteLine("C:\t" + Context.EnsureAtLeastLength(t.Name, 20) + "\t" + t.FullName);
    }
}

public void ListDir(String match) {
    Regex re = match != null ? new Regex(match) : null;
    foreach (TypeDictionary dic in SubTypeDictionary.Values) {
        if (re != null && !re.IsMatch(dic.Name)) continue;
        Console.WriteLine("N:\t" + Context.EnsureAtLeastLength(dic.Name, 20) + "\t" + dic.FullName);
    }
}

4. 類型成員檢視 (擴充方法)

利用 C# 擴充方法簡化呼叫語法,可直接對 Type 或 Object 執行個體呼叫 .methods()、.props()、.members()、.creaters():

public static class ClassExtensionMethods {
    public static void methods(this Type t) {
        foreach (MethodInfo mi in t.GetMethods()) Console.WriteLine(" " + mi);
    }
    public static void methods(this Object obj) { if (obj != null) methods(obj.GetType()); }
    // props, members, creaters 同理...
}

二、動態代碼片段執行 (CscCmdHandler)

核心邏輯在 Run() 方法:將使用者輸入包裝在動態產生的類別 DynamicClass.MethodInstance 中,自動引入當前命名空間與常用命名空間,透過 CSharpCodeProvider 記憶體編譯並執行。

public override void Run() {
    if (String.IsNullOrEmpty(InputCmdString)) return;
    String fullCmd = String.Empty;
    if (Context.TypeManager.Now != Context.TypeManager.Root)
        fullCmd += " using " + Context.TypeManager.Now.FullName + ";";
    fullCmd += @"
        using System; using System.IO; using System.Text;
        using System.Collections.Generic; using Orc.Shell.Core;
        namespace Orc.Shell.Core.Dynamic {
            public class DynamicClass {
                public Orc.Shell.Core.Context Context;
                public void Save(String name, Object obj) { Context.Save(name, obj); }
                public Object My(String name) { return Context[name]; }
                public void MethodInstance(Context context) { Context = context; " + InputCmdString + @"; }
            }
        }";

    CompilerResults cr = Context.CodeProvider.CompileAssemblyFromSource(Context.CompilerParameters, fullCmd);
    if (cr.Errors.HasErrors) { /* 輸出錯誤 */ }
    else {
        Assembly assem = cr.CompiledAssembly;
        Object dynamicObject = assem.CreateInstance("Orc.Shell.Core.Dynamic.DynamicClass");
        Type t = assem.GetType("Orc.Shell.Core.Dynamic.DynamicClass");
        MethodInfo minfo = t.GetMethod("MethodInstance");
        minfo.Invoke(dynamicObject, new Object[] { Context });
    }
}

編譯器參數初始化

CodeProvider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v3.5" } });
CompilerParameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll", "Orc.Shell.Core.dll", "OrcShell.exe" });
CompilerParameters.GenerateExecutable = false;
CompilerParameters.GenerateInMemory = true;

環境變數互動:Save(name, obj) 存入內容變數,My(name) 取出。另有 my 指令列出所有變數。

三、實用擴充與別名系統

1. 列印捷徑

public static void p(this Object obj) { Console.WriteLine(obj); }
public static void P(this Object obj) { Console.WriteLine(obj); }
public static void print(this Object obj) { Console.WriteLine(obj); }

2. 指令別名 (Alias.xml)

可編輯專案目錄下的 Alias.xml 自訂指令縮寫,Alias 指令可查看目前定義。

四、待完成功能

  • 手動載入程序集
  • 常用系統管理指令
  • 遠端控制支援
  • 指令自動完成 (Tab Completion)

OrcShell 雖為原型,但展示了利用 .NET 反射與動態編譯打造 REPL 環境的可行路徑,為進階診斷工具或教學輔助奠定基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved