二、类型管理
1、程序集与类型的管理
在Context初始化时便将AppDomain中的类型全部加载并交给TypeManager管理:
public
Context()
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
……
TypeManager = new TypeManager();
Assemblys = new Dictionary<String, Assembly>();
Assembly[] al = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly a in al)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
AddAssembly(a);
}
![](/Images/OutliningIndicators/InBlock.gif)
AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);
……
}
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
private
void
AddAssembly(Assembly a)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
if (a != null)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Assemblys.Add(a.FullName, a);
Type[] tl = a.GetTypes();
![](/Images/OutliningIndicators/InBlock.gif)
foreach (Type t in tl)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if(!t.FullName.StartsWith("<PrivateImplementationDetails>"))
TypeManager.AddType(t);
}
}
}
![](/Images/OutliningIndicators/None.gif)
void
CurrentDomain_AssemblyLoad(
object
sender, AssemblyLoadEventArgs args)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
Assembly a = args.LoadedAssembly;
if (!Assemblys.ContainsKey(a.FullName))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
Regex re = null;
![](/Images/OutliningIndicators/InBlock.gif)
if (match != null)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
re = new Regex(match);
}
![](/Images/OutliningIndicators/InBlock.gif)
foreach (Type t in Types.Values)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
String name = t.Name;
if (re != null)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (!re.IsMatch(name)) continue;
}
Console.WriteLine("C:\t" + Context.EnsureAtLeastLength(name,20) + "\t" + t.FullName);
}
}
![](/Images/OutliningIndicators/None.gif)
public
void
ListDir(String match)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
Regex re = null;
![](/Images/OutliningIndicators/InBlock.gif)
if (match != null)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
re = new Regex(match);
}
![](/Images/OutliningIndicators/InBlock.gif)
foreach (TypeDictionary dic in SubTypeDictionary.Values)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
String name = dic.Name;
if (re != null)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (!re.IsMatch(name)) continue;
}
Console.WriteLine("N:\t" + Context.EnsureAtLeastLength(name, 20) + "\t" + dic.FullName);
}
}
4、查看类型
扩展方法确实是好东西,有了它这里实现起来很简单。在 ClassExtensionMethods里 实现:
public
static
class
ClassExtensionMethods
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
……
public static void methods(this Type t)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (MethodInfo mi in t.GetMethods())
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" " + mi);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void methods(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (obj == null) return;
![](/Images/OutliningIndicators/InBlock.gif)
methods(obj.GetType());
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void props(this Type t)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (PropertyInfo pi in t.GetProperties())
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" " + pi);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void props(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (obj == null) return;
![](/Images/OutliningIndicators/InBlock.gif)
props(obj.GetType());
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void members(this Type t)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (MemberInfo mi in t.GetMembers())
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" " + mi);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void members(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (obj == null) return;
![](/Images/OutliningIndicators/InBlock.gif)
members(obj.GetType());
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void creaters(this Type t)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (ConstructorInfo ci in t.GetConstructors())
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" " + ci);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void creaters(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (obj == null) return;
![](/Images/OutliningIndicators/InBlock.gif)
creaters(obj.GetType());
}
}
三、执行代码片断
在 CscCmdHandler 中实现。核心方法为 CscCmdHandler.Run(),代码如下:
public
override
void
Run()
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
if (String.IsNullOrEmpty(InputCmdString)) return;
String fullCmd = String.Empty;
if (Context.TypeManager.Now != Context.TypeManager.Root)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
fullCmd += " using " + Context.TypeManager.Now.FullName + ";";
}
fullCmd +=
@" using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using Orc.Shell.Core;
![](/Images/OutliningIndicators/InBlock.gif)
namespace Orc.Shell.Core.Dynamic
{
public class DynamicClass
{
public Orc.Shell.Core.Context Context;
![](/Images/OutliningIndicators/InBlock.gif)
public void Save(String name, Object obj)
{
Context.Save(name,obj);
}
![](/Images/OutliningIndicators/InBlock.gif)
public Object My(String name)
{
return Context[name];
}
![](/Images/OutliningIndicators/InBlock.gif)
public void MethodInstance(Context context)
{
Context = context;
" + InputCmdString + @";
}
}
}";
![](/Images/OutliningIndicators/InBlock.gif)
CompilerResults cr = Context.CodeProvider.CompileAssemblyFromSource(Context.CompilerParameters, fullCmd);
![](/Images/OutliningIndicators/InBlock.gif)
if (Context.Debug)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("Source:");
Console.WriteLine("--------------------------------");
Console.WriteLine(fullCmd);
Console.WriteLine("--------------------------------");
Console.WriteLine("Results");
}
![](/Images/OutliningIndicators/InBlock.gif)
if (cr.Errors.HasErrors)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("编译错误:");
foreach (CompilerError err in cr.Errors)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (Context.Debug)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(String.Format("line {0}: {1}", err.Line, err.ErrorText));
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(err.ErrorText);
}
}
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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");
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
minfo.Invoke(dynamicObject, new Object[]
{ Context });
}
}
其中 CodeProvider,CompilerParameters 在 Context 中初始化:
CodeProvider
=
new
CSharpCodeProvider(
new
Dictionary
<
string
,
string
>
()
{
{ "CompilerVersion", "v3.5" } }
);
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
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
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public static void Print(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(obj);
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void p(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Print( obj );
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void P(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Print(obj);
}
![](/Images/OutliningIndicators/InBlock.gif)
public static void print(this Object obj)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Print(obj);
}
……
}
2、变量缩写(Alias)
指令缩写可明显降低操作量。可通过编辑程序集目录下的 Alias.xml 文件来添加、删除或更改指令缩写。
Alias 指令可以查看目前的指令缩写。
五、缺乏的功能。
到现在为止,OrcShell只实现了Shell的雏型。由于只开发了一个晚上,测试也不是很完善,另外许多重要功能还未涉及,主要包括:
1、手动加载程序集;
2、常用系统管理功能,如常用的Shell 指令;
3、远程控制;
4、指令的自动完成。
留待后续。