找回密码
 立即注册

QQ登录

只需一步,快速开始

thrall

超级版主

11

主题

170

帖子

1903

积分

超级版主

Rank: 8Rank: 8

积分
1903

活字格认证微信认证勋章

thrall
超级版主   /  发表于:2013-5-7 10:10  /   查看:5262  /  回复:0
我们经常会有这样的需求或者想法:动态的生成或者修改代码。当然,我们可以把代码看成字符串而直接修改,但是这种做法也未免太生硬了,能解决的问题有限;而另一个方式就是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:
  1. public class MyComponent1 : Component   
  2. {        
  3.         public MyComponent1()        
  4.         {           
  5.                  textBox1 = new TextBox();           
  6.                  textBox1.BackColor = Color.Red;        
  7.         }

  8.         private int int1;        
  9.         private TextBox textBox1;        
  10.        
  11.         public int IntProperty        
  12.         {            
  13.                 get { return int1; }            
  14.                 set { int1 = value; }
  15.         }        

  16.         public TextBox TextBoxProperty        
  17.         {
  18.                 get { return textBox1; }            
  19.         }
  20. }
复制代码
接着创建另一个WindowsFormsApplication项目:CodeDomSample,并引用System.Design和WindowsControlLibrary1项目(当然,你也可以把WindowsControlLibrary1编译成dll并引用这个dll)现在,创建我们的核心类CodeTypeConverter,对于具体实现我不做过多的说明,你不必要关心实现的具体细节,只要这个实现能够满足你的需求就行了。如果你有看不明白的地方请提问,我会认真回答。
  1. public class CodeTypeConverter
  2.     {
  3.         private IServiceProvider _serviceProvider;

  4.         private IDesignerHost DesignerHost
  5.         {
  6.             get
  7.             {
  8.                 return this._serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
  9.             }
  10.         }

  11.         //将Component Load到DesignerHost中并返回
  12.         private IComponent LoadComponent(IComponent component)
  13.         {
  14.             DesignSurfaceManager manager = new DesignSurfaceManager();
  15.             DesignSurface surface = manager.CreateDesignSurface();
  16.             surface.BeginLoad(component.GetType());
  17.             this._serviceProvider = surface;
  18.             IComponent newComponent = DesignerHost.RootComponent;
  19.             //暴力克隆,将component上的所有Field设到newComponent上
  20.             FieldInfo[] fields = component.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
  21.             foreach (FieldInfo field in fields)
  22.             {
  23.                 object fieldValue = field.GetValue(component);
  24.                 //将所有子Component Load到DesignerHost中
  25.                 if (fieldValue != null && fieldValue is IComponent)
  26.                 {
  27.                     DesignerHost.Container.Add(fieldValue as IComponent, field.Name);
  28.                 }
  29.                 field.SetValue(newComponent, fieldValue);
  30.             }
  31.             return newComponent;
  32.         }
  33.    
  34.         //将DesignerHost中的Component转成CodeType
  35.         public CodeTypeDeclaration ConvertComponentToCodeType(IComponent component)
  36.         {
  37.             component = this.LoadComponent(component) as Component;
  38.             DesignerSerializationManager manager = new DesignerSerializationManager(this._serviceProvider);
  39.             //这句Code是必须的,必须要有一个session,DesignerSerializationManager才能工作
  40.             IDisposable session = manager.CreateSession();
  41.             TypeCodeDomSerializer serializer = manager.GetSerializer(component.GetType(), typeof(TypeCodeDomSerializer)) as TypeCodeDomSerializer;
  42.             List<object> list = new List<object>();
  43.             foreach (IComponent item in this.DesignerHost.Container.Components)
  44.             {
  45.                 list.Add(item);
  46.             }
  47.             CodeTypeDeclaration declaration = serializer.Serialize(manager, component, list);
  48.             session.Dispose();
  49.             return declaration;
  50.         }
  51. }
复制代码
好了,CodeTypeConverter实现完成。现在在Form1中写一个Test方法测试:
  1. public Form1()
  2.         {
  3.             InitializeComponent();
  4.             Test();
  5.         }

  6.         public void Test()
  7.         {
  8.             CodeTypeConverter designerHost = new CodeTypeConverter();
  9.             MyComponent1 component = new MyComponent1();
  10.             component.IntProperty = 10;
  11.             component.TextBoxProperty.Text = "Hello World";

  12.             CodeTypeDeclaration componentType = designerHost.ConvertComponentToCodeType(component);
  13.             componentType.Name = component.GetType().Name + "1";

  14.             StringBuilder bulder = new StringBuilder();
  15.             StringWriter writer = new StringWriter(bulder, CultureInfo.InvariantCulture);
  16.             CodeGeneratorOptions option = new CodeGeneratorOptions();
  17.             option.BracingStyle = "C";
  18.             option.BlankLinesBetweenMembers = false;
  19.             CSharpCodeProvider codeDomProvider = new CSharpCodeProvider();
  20.             codeDomProvider.GenerateCodeFromType(componentType, writer, option);
  21.             Debug.WriteLine(bulder.ToString());
  22.             writer.Close();
  23.         }
复制代码

CodeDomSample跑起来以后,就可以在输出窗口看到如下的输出:
  1. public class MyComponent11 : WindowsControlLibrary1.MyComponent1
  2. {
  3.     private System.Windows.Forms.TextBox textBox1;
  4.     private MyComponent11()
  5.     {
  6.         this.InitializeComponent();
  7.     }
  8.     private void InitializeComponent()
  9.     {
  10.         this.textBox1 = new System.Windows.Forms.TextBox();
  11.         //
  12.         // textBox1
  13.         //
  14.         this.textBox1.BackColor = System.Drawing.Color.Red;
  15.         this.textBox1.Location = new System.Drawing.Point(0, 0);
  16.         this.textBox1.Name = "textBox1";
  17.         this.textBox1.Size = new System.Drawing.Size(100, 20);
  18.         this.textBox1.TabIndex = 0;
  19.         this.textBox1.Text = "Hello World";
  20.         //
  21.         //
  22.         //
  23.         this.IntProperty = 10;
  24.     }
  25. }
复制代码


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

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部