• 实现简单的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<stringstring>() "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、指令的自动完成。

    留待后续。

    版权所有,欢迎转载
  • 相关阅读:
    zookeeper项目使用几点小结
    Dubbo架构设计详解
    关于web.xml不同版本之间的区别
    bat定时执行,清除PHP缓存
    新闻列表标题省略样式
    php把时间格式化
    HTML5中的拖放
    Redis JAVA客户端 Jedis常用方法
    Redis 简介
    SpringBoot DataSource 配置说明
  • 原文地址:https://www.cnblogs.com/xiaotie/p/1085834.html
Copyright © 2020-2023  润新知