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

 

 

 

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

posted on 2010-08-20 12:29  cylj.xu  阅读(2219)  评论(19编辑  收藏  举报