程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 實現簡單的CSharpShell -- OrcShell (2) 類型浏覽、執行代碼片斷與其它

實現簡單的CSharpShell -- OrcShell (2) 類型浏覽、執行代碼片斷與其它

編輯:關於.NET

二、類型管理

1、程序集與類型的管理

在Context初始化時便將AppDomain中的類型全部加載並交給TypeManager管理:

    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 += new AssemblyLoadEventHandler

(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);
      }
    }

開發時發現,程序集中有一批類型名字以"<PrivateImplementationDetails>"開頭的類型,貌 似時臨時類型,這些東西數量較多,干脆把它屏蔽掉了。

2、進出命名空間

在CdClassCmdHandler 中實現,目前不支持級聯操作,即:cdc ..;cdc .; cdc namespaceName這樣 是可以的,cdc ../ns1/ns2 這樣是不支持的。輸入的命名空間名稱可以只是部分,程序自動進行匹配, 如只有1個匹配項則自動進入該項,否則不進行操作,同時打印所有匹配項。

3、列出命名空間和類型

在 ListClassCmdHandler 中實現,支持正則表達式匹配。幕後工作由TypeDictionary在做:

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

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

dic.FullName);
      }
    }

4、查看類型

擴展方法確實是好東西,有了它這裡實現起來很簡單。在 ClassExtensionMethods裡 實現:

  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) return;
      methods(obj.GetType());
    }
    public static void props(this Type t)
    {
      foreach (PropertyInfo pi in t.GetProperties())
      {
        Console.WriteLine(" " + pi);
      }
    }
    public static void props(this Object obj)
    {
      if (obj == null) return;
      props(obj.GetType());
    }
    public static void members(this Type t)
    {
      foreach (MemberInfo mi in t.GetMembers())
      {
        Console.WriteLine(" " + mi);
      }
    }
    public static void members(this Object obj)
    {
      if (obj == null) return;
      members(obj.GetType());
    }
    public static void creaters(this Type t)
    {
      foreach (ConstructorInfo ci in t.GetConstructors())
      {
        Console.WriteLine(" " + ci);
      }
    }
    public static void creaters(this Object obj)
    {
      if (obj == null) return;
      creaters(obj.GetType());
    }
  }

三、執行代碼片斷

在 CscCmdHandler 中實現。核心方法為 CscCmdHandler.Run(),代碼如下:

    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 (Context.Debug)
      {
        Console.WriteLine("Source:");
        Console.WriteLine("--------------------------------");
        Console.WriteLine(fullCmd);
        Console.WriteLine("--------------------------------");
        Console.WriteLine("Results");
      }
      if (cr.Errors.HasErrors)
      {
        Console.WriteLine("編譯錯誤:");
        foreach (CompilerError err in cr.Errors)
        {
          if (Context.Debug)
          {
            Console.WriteLine(String.Format("line {0}: {1}", err.Line, 

err.ErrorText));
          }
          else
          {
            Console.WriteLine(err.ErrorText);
          }
        }
      }
      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,CompilerParameters 在 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(String name, Object obj) 和 My(String name) 來同環境進行交互。其中,Save (String name, Object obj) 是將代碼片斷中的對象 obj 保存為環境變量,變量名稱為 name。My (String name)取出名稱為name 的環境變量,加載到代碼段上。my 指令可以查看所有環境變量。

采用$name的方式操作環境變量更簡介、直觀,但這樣一來代碼難度加大不少,沒想到什麼簡潔的實現 ,就沒采用。

四、其它

1、擴展方法

對於常用的方法通過擴展方法來方便使用。如,打印一個對象 obj 到控制台上,正常寫法是 System.Console.WriteLine(obj.ToString()),比較麻煩,通過擴展方法,可以使它簡化為:obj.p();相 關代碼如下:

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

2、變量縮寫(Alias)

指令縮寫可明顯降低操作量。可通過編輯程序集目錄下的 Alias.xml 文件來添加、刪除或更改指令縮 寫。

Alias 指令可以查看目前的指令縮寫。

五、缺乏的功能。

到現在為止,OrcShell只實現了Shell的雛型。由於只開發了一個晚上,測試也不是很完善,另外許多 重要功能還未涉及,主要包括:

1、手動加載程序集;

2、常用系統管理功能,如常用的Shell 指令;

3、遠程控制;

4、指令的自動完成。

留待後續。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved