技术开发 频道

VS集成之代码生成机制实现强类型编程

    【IT168 技术文档】我不知道大家对CodeDOM的代码生成机制是否熟悉,但是有一点可以确定:如果你使用过Visual Studio,你就应该体验过它带给我们在编程上的便利。随便列举三种典型的代码生成的场景:在创建强类型DataSet的时候,VS会自动根据Schema生成相应的C#或者VB.NET代码;当我们编辑Resource文件的时候,相应的的后台代码也会自动生成;当我们通过添加Web Reference调用Web Service或者WCF Service的时候,VS会自动生成服务代理的代码和相应的配置。总的来说,通过和VS集成的动态代码生成工具使我们可以“强类型”的方式进行编程,进而提供我们的效率并减低错误的几率。

  实际上,除了VS提供的这些典型的代码生成场景中,我们可以根据需要开发一些自定义代码生成器,并且通过VS的扩展实现后台代码的实时生成,从而实现强类型编程的目的,现在我们举一个典型的应用场景——消息管理。

  一、一个典型的自定义代码生成器应用场景——消息管理

  无论对于怎么样的应用,我们都需要维护一系列的消息。消息的类型很多,比如验证消息、确认消息、日志消息等。我们一般会将消息储存在一个文件或者数据库中进行维护,并提供一些API来获取相应的消息项。这些API一般都是基于消息的ID来获取的,换句话说,消息获取的方式是以一种“弱类型”的编程方式实现的。如果我们能够根据消息存储的内容动态地生成相应的C#或者VB.NET代码,那么我们就能够以一种强类型的方式来获取相应的消息项了。

  比如说,现在我们定义了如下一个MessageEntry类型来表示一个消息条目。为了简单,我们尽量简化MessageEntry的定义,仅仅保留三个属性Id、Value和Category。Category表示该消息条目所属的类型,你可以根据具体的需要对其分类(比如根据模块名称或者Severity等)。Value是一个消息真实的内容,可以包含一些占位符({0},{1},…{N})。通过指定占位符对用的值,最中格式化后的文本通过Format返回。

public class MessageEntry  
{  
    
public string Id { get; private set; }  
    
public string Value { get; private set; }  
    
public string Category { get; private set; }  
    
public MessageEntry(string id, string value, string category)  
     {  
         this.Id        
= id;  
         this.Value      
= value;  
         this.Category  
= category;  
     }  
    
public string Format(params object[] args)  
     {  
         return
string.Format(this.Value, args);  
     }  
}

 

  现在我们所有的消息定义在如下一个XML文件中,XML元素代码一个具体的MessageEntry,相应的属性(Attribute)和MessageEntry的属性(Property)相对应。

<?xml version="1.0" encoding="utf-8" ?>  
<messages>  
  
<message id="MandatoryField" value="The {0} is mandatory."  category="Validation"/>  
  
<message id="GreaterThan" value="The {0} must be greater than {1}."  category="Validation"/>  
  
<message id="ReallyDelete" value="Do you really want to delete the {0}."  category="Confirmation"/>  
</messages>

 

  在上面的XML中,定义了两个类别(Validation和Confirmation)的三条MessageEntry。我们需要通过我们的代码生成工具生成一个包含如下C#代码的CS文件。

namespace Artech.CodeDomGenerator  
{        
    
public class Messages  
     {          
        
public class Validation  
         {              
            
public static Artech.CodeDomGenerator.MessageEntry MandatoryField = new Artech.CodeDomGenerator.MessageEntry("MandatoryField", "The {0} is mandatory.", "Validation");  
            
public static Artech.CodeDomGenerator.MessageEntry GreaterThan = new Artech.CodeDomGenerator.MessageEntry("GreaterThan", "The {0} must be greater than {1}.", "Validation");  
         }          
        
public class Confirmation  
         {              
            
public static Artech.CodeDomGenerator.MessageEntry ReallyDelete = new Artech.CodeDomGenerator.MessageEntry("ReallyDelete", "Do you really want to delete the {0}.", "Confirmation");  
         }  
     }  
}

 

  那么我们就能够直接通过生成出来的Messages类,以强类型的方式获取并格式化每一条MessageEntry的内容了。

Console.WriteLine(Messages.Validation.MandatoryField.Format("User Name"));  
Console.WriteLine(Messages.Validation.GreaterThan.Format(
"Age",18));  
Console.WriteLine(Messages.Confirmation.ReallyDelete.Format(
"Order record"));

 

  下面是输出结果:

The User Name is mandatory.  
The Age must be greater than
18.  
Do you really want to delete the Order record.

 

  要实现上面的功能实际上包含两个步骤:一是动态解析包含消息定义的XML文件,并生成我们希望结构的一个代码定义,而是通过和VS进行集成,借助VS自定义工具将前面生成的内容真正写入到一个具体的.cs文件中。第一个步骤可以通过CodeDOM轻松实现,而第二个步骤借助于VS的扩展也会很简单。本篇文章我们只关注第一个方面,下面我们在对第二个方面进行介绍。 

0
相关文章