zoukankan      html  css  js  c++  java
  • 从Component对象到CodeDom——舞动你的Code系列(1)

    我们经常会有这样的需求或者想法:动态的生成或者修改代码。当然,我们可以把代码看成字符串而直接修改,但是这种做法也未免太生硬了,能解决的问题有限;而另一个方式就是CodeDom。

    CodeDom是强大的!我们感谢微软,给我们提供了强大的描述面向对象语言的框架;我们感谢微软,给我们提供了能够根据CodeDom生成代码或者程序集的CodeDomProvider;可惜微软没有给我们提供能够从object或者代码生成CodeDom的能力。

    关于CodeDom的知识本文不过多涉及、感兴趣的童鞋可以阅读MSDN或者博客园的其它文章学习了解。本系列期望解决的问题就是如何将对象或者代码生成CodeDom。当然,由于微软并没有提供这样的支持,而我也不可能写一个解析C#语言或者VB语言的CodeParser,所以本文提供的方案也能力有限,但愿能够解决你的一部分问题或者给您能学到点知识。

    这是本系列的第一篇文章,如何让一个Component对象生成CodeDom。核心思想就是虚拟一个DesignTime的环境,并将Component添加到Designer中,然后使用ComponentTypeCodeDomSerializer将Component序列化成CodeTypeDeclaration。本方案可以在任意程序下执行,不依赖IDE,也不需要引用各种奇怪的dll。

    下面就是具体实现:

    首先,创建一个WindowsControlLibrary,名叫WindowsControlLibrary1。

    然后,添加一个类取名MyComponent1,类中有一个GetSet的属性IntProperty,还有一个设置了背景色的TextBox:

    public class MyComponent1 : Component    
    {        
    	public MyComponent1()        
    	{           
    		 textBox1 = new TextBox();           
    		 textBox1.BackColor = Color.Red;        
    	}
    
    	private int int1;        
    	private TextBox textBox1;        
    	
    	public int IntProperty        
    	{            
    		get { return int1; }            
    		set { int1 = value; } 
    	}        
    
    	public TextBox TextBoxProperty        
    	{
    		get { return textBox1; }            
    	}
    }

    接着创建另一个WindowsFormsApplication项目:CodeDomSample,并引用System.Design和WindowsControlLibrary1项目(当然,你也可以把WindowsControlLibrary1编译成dll并引用这个dll)

    现在,创建我们的核心类CodeTypeConverter,对于具体实现我不做过多的说明,你不必要关心实现的具体细节,只要这个实现能够满足你的需求就行了。如果你有看不明白的地方请提问,我会认真回答。

        public class CodeTypeConverter
        {
            private IServiceProvider _serviceProvider;
    
            private IDesignerHost DesignerHost
            {
                get
                {
                    return this._serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
                }
            }
    
            //将Component Load到DesignerHost中并返回
            private IComponent LoadComponent(IComponent component)
            {
                DesignSurfaceManager manager = new DesignSurfaceManager();
                DesignSurface surface = manager.CreateDesignSurface();
                surface.BeginLoad(component.GetType());
                this._serviceProvider = surface;
                IComponent newComponent = DesignerHost.RootComponent;
                //暴力克隆,将component上的所有Field设到newComponent上
                FieldInfo[] fields = component.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
                foreach (FieldInfo field in fields)
                {
                    object fieldValue = field.GetValue(component);
                    //将所有子Component Load到DesignerHost中
                    if (fieldValue != null && fieldValue is IComponent)
                    {
                        DesignerHost.Container.Add(fieldValue as IComponent, field.Name);
                    }
                    field.SetValue(newComponent, fieldValue);
                }
                return newComponent;
            }
        
            //将DesignerHost中的Component转成CodeType
            public CodeTypeDeclaration ConvertComponentToCodeType(IComponent component)
            {
                component = this.LoadComponent(component) as Component;
                DesignerSerializationManager manager = new DesignerSerializationManager(this._serviceProvider);
                //这句Code是必须的,必须要有一个session,DesignerSerializationManager才能工作
                IDisposable session = manager.CreateSession();
                TypeCodeDomSerializer serializer = manager.GetSerializer(component.GetType(), typeof(TypeCodeDomSerializer)) as TypeCodeDomSerializer;
                List<object> list = new List<object>();
                foreach (IComponent item in this.DesignerHost.Container.Components)
                {
                    list.Add(item);
                }
                CodeTypeDeclaration declaration = serializer.Serialize(manager, component, list);
                session.Dispose();
                return declaration;
            }
    }

    好了,CodeTypeConverter实现完成。现在在Form1中写一个Test方法测试:

            public Form1()
            {
                InitializeComponent();
                Test();
            }
    
            public void Test()
            {
                CodeTypeConverter designerHost = new CodeTypeConverter();
                MyComponent1 component = new MyComponent1();
                component.IntProperty = 10;
                component.TextBoxProperty.Text = "Hello World";
    
                CodeTypeDeclaration componentType = designerHost.ConvertComponentToCodeType(component);
                componentType.Name = component.GetType().Name + "1";
    
                StringBuilder bulder = new StringBuilder();
                StringWriter writer = new StringWriter(bulder, CultureInfo.InvariantCulture);
                CodeGeneratorOptions option = new CodeGeneratorOptions();
                option.BracingStyle = "C";
                option.BlankLinesBetweenMembers = false;
                CSharpCodeProvider codeDomProvider = new CSharpCodeProvider();
                codeDomProvider.GenerateCodeFromType(componentType, writer, option);
                Debug.WriteLine(bulder.ToString());
                writer.Close();
            }

    CodeDomSample跑起来以后,就可以在输出窗口看到如下的输出:

    public class MyComponent11 : WindowsControlLibrary1.MyComponent1
    {
        private System.Windows.Forms.TextBox textBox1;
        private MyComponent11()
        {
            this.InitializeComponent();
        }
        private void InitializeComponent()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            // 
            // textBox1
            // 
            this.textBox1.BackColor = System.Drawing.Color.Red;
            this.textBox1.Location = new System.Drawing.Point(0, 0);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(100, 20);
            this.textBox1.TabIndex = 0;
            this.textBox1.Text = "Hello World";
            // 
            // 
            // 
            this.IntProperty = 10;
        }
    }

    搞定收工。欢迎提问以及拍砖灌水,更欢迎掌声鲜花。



    本文是由葡萄城技术开发团队发布,转载请注明出处:葡萄城官网


  • 相关阅读:
    Java 1 (JVM、JRE、JDK之间的关系)
    Java 0 (jdk下载安装及环境配置)
    推荐之链接
    idea 2019激活码
    Mock数据使用的Util
    mybatis慢查询配置
    logback参考配置
    Linux网络实时监控配置
    jmeter插件JMeterPlugins-Standard 压力测试
    ZoneDateTime 转换Date
  • 原文地址:https://www.cnblogs.com/powertoolsteam/p/1807269.html
Copyright © 2011-2022 走看看