从Component对象到CodeDom——舞动你的Code系列(1)

简介: 我们经常会有这样的需求或者想法:动态的生成或者修改代码。当然,我们可以把代码看成字符串而直接修改,但是这种做法也未免太生硬了,能解决的问题有限;而另一个方式就是CodeDom。 CodeDom是强大的!我们感谢微软,给我们提供了强大的描述面向对象语言的框架;我们感谢微软,给我们提供了能够根据CodeDom生成代码或者程序集的CodeDomProvider;可惜微软没有给我们提供能够从object或者代码生成CodeDom的能力。

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

 

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

相关文章
|
6月前
|
存储 API 数据库
【Entity Framework】Code First 数据批注
【Entity Framework】Code First 数据批注
45 0
|
存储 安全 程序员
2000条你应知的WPF小姿势 基础篇<34-39 Unhandled Exceptions和Resource>
2000条你应知的WPF小姿势 基础篇<34-39 Unhandled Exceptions和Resource>
36 0
2000条你应知的WPF小姿势 基础篇<34-39 Unhandled Exceptions和Resource>
|
缓存 前端开发 中间件
Lumen报class does not exist的mailer坑
Lumen报class does not exist的mailer坑
170 0
|
数据库
艾伟_转载:Entity Framework的默认值BUG解决方法
  在使用.Net 3.5里的Entity Framework开发网站的时候,遇到了一个问题:添加记录时,对于DateTime型的数据,无法使用数据库的默认值。   具体的情况是这样的,我的数据库有个Users表,三个字段,id,username,createtime。
850 0
艾伟_转载:一个简单的 Generic Factory 类
  简单的工厂类的一个使用场景是, 假设有一个基类 BaseClass, 和一系列的子类 A, B, C, 工厂类根据某个参数,例如字符串 “A”, “B”, “C” 创建出相应的子类。 举例如下: public class Factory { public static BaseClass...
621 0
|
存储 缓存 弹性计算
Unity Entity Component System 理论知识总结
今天跟同学们分享一下我找到的关于ECS相关的理论知识文章,可能比较枯燥,如果想看实操的请看我下方写的一些案例解析。 Unity之浅析 Entity Component System (ECS) Unity 之 Pure版Entity Compon...
1991 0
|
JavaScript Android开发
|
JavaScript Android开发 iOS开发
|
XML JavaScript C#
第七章:XAML vs. code(3)
属性元素语法这里有一些C#与第4章中的FramedText代码相似。在一个语句中,它实例化一个Frame和一个Label,并将Label设置为Frame的Content属性: new Frame { OutlineColor = Color.
912 0