实现简单的CSharpShell -- OrcShell (2) 类型浏览、执行代码片断与其它

简介:
  二、类型管理

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 == nullreturn;

            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 == nullreturn;

            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 == nullreturn;

            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 == nullreturn;

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

        }

其中 CodeProviderCompilerParameters   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 保存为环境变量,变量名称为 nameMy(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、指令的自动完成。

留待后续。

本文转自xiaotie博客园博客,原文链接http://www.cnblogs.com/xiaotie/archive/2008/02/29/1085834.html如需转载请自行联系原作者


xiaotie 集异璧实验室(GEBLAB)

相关文章
|
7月前
|
Java API 调度
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
372 0
|
5月前
|
Java 数据库连接 应用服务中间件
表单数据返回不到,HTTP状态 404 - 未找未找到,解决方法,针对这个问题,写一篇文章,理一下思路,仔细与原项目比对,犯错的原因是Mapper层的select查询表单数据写错,注意打开的路径对不对
表单数据返回不到,HTTP状态 404 - 未找未找到,解决方法,针对这个问题,写一篇文章,理一下思路,仔细与原项目比对,犯错的原因是Mapper层的select查询表单数据写错,注意打开的路径对不对
|
7月前
|
开发者
在用户关闭页面时,提示用户有内容未保存-论onbeforeunload事件的用法
在用户关闭页面时,提示用户有内容未保存-论onbeforeunload事件的用法
125 0
|
7月前
|
前端开发 JavaScript
empty来显示暂无数据简直太好用,阻止用户复制文本user-select
empty来显示暂无数据简直太好用,阻止用户复制文本user-select
element中的el-select中多选回显数据后没法重新选择和更改
element中的el-select中多选回显数据后没法重新选择和更改
|
JavaScript 前端开发
如何阻止在 vue项目中快速双击俩次新增/编辑连续发送俩次请求
如何阻止在 vue项目中快速双击俩次新增/编辑连续发送俩次请求
93 0
element close事件关闭表单,数据替换掉原始列表的数据bug解决
element close事件关闭表单,数据替换掉原始列表的数据bug解决
79 0
|
Shell 网络安全 数据安全/隐私保护