技术开发 频道

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

  这是C#代码(和我们开始提到过的完全一致):

<auto-generated>  
     This code was generated by a tool.  
     Runtime Version:
4.0.30319.1      
     Changes
to this file may cause incorrect behavior and will be lost if  
     the code
is regenerated.  
</auto-generated>      
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");  
         }  
     }  
}

 

  下面是VB.NET代码:

<auto-generated>  
     This code was generated by a tool.  
     Runtime Version:
4.0.30319.1      
     Changes
to this file may cause incorrect behavior and will be lost if  
     the code
is regenerated.  
</auto-generated>      
Option Strict Off  
Option Explicit On    
    
Namespace Artech.CodeDomGenerator        
    
Public Class Messages            
        
Public Class Validation  
              
            
Public Shared MandatoryField As Artech.CodeDomGenerator.MessageEntry = New Artech.CodeDomGenerator.MessageEntry("MandatoryField", "The {0} is mandatory.", "Validation")  
              
            
Public Shared GreaterThan As Artech.CodeDomGenerator.MessageEntry = New Artech.CodeDomGenerator.MessageEntry("GreaterThan", "The {0} must be greater than {1}.", "Validation")  
        
End Class  
          
        
Public Class Confirmation  
              
            
Public Shared ReallyDelete As Artech.CodeDomGenerator.MessageEntry = New Artech.CodeDomGenerator.MessageEntry("ReallyDelete", "Do you really want to delete the {0}.", "Confirmation")  
        
End Class  
    
End Class  
End Namespace

 

  在前面,我们实现了将保存有消息条目的XML向CodeDOM的转换,即是将XML文件生成一个CodeCompileUnit对象,而该CodeCompileUnit对象反映出来的DOM层次和我们将会生成的代码文件向匹配。在下篇中,我们将实现整个代码生成系统的第二个步骤——通过VS的Custom Tool实现数据(保存消息条目的XML)向代码文件的自动转换。

  一、让MessageCodeGenerator继承BaseCodeGeneratorWithSite

  在前面我们创建了MessageCodeGenerator类,定义了如下一个BuildCodeObject方法实现将一个XmlDocument转换成一个CodeCompileUnit对象。

namespace Artech.CodeDomGenerator  
{  
    
public class MessageCodeGenerator  
     {        
        
// Others...  
        
public CodeCompileUnit BuildCodeObject(XmlDocument messages);  
     }  
}

 

  现在我们需要做的是让这个MessageCodeGenerator继承一个特殊的类:BaseCodeGeneratorWithSite。BaseCodeGeneratorWithSite所在的程序集名称为Microsoft.VisualStudio.TextTemplating.VSHost.10.0.dll,这是一个Visual Studio SDK的程序集。我们例子采用的是Visual Studio 2010,你可以在如下的目录中找到该程序集:%ProgramFiles%Microsoft Visual Studio 2010 SDK\VisualStudioIntegration\Common\Assemblies\v4.0。如果你没有安装VS 2010 SDK,你可以从这里下载。

  除了添加对Microsoft.VisualStudio.TextTemplating.VSHost.10.0.dll程序集的引用外,你还需要添加两个额外的程序集引用:Microsoft.VisualStudio.OLE.Interop.dll和Microsoft.VisualStudio.Shell.Interop.dll,它们所在的目录分别是%ProgramFiles%Microsoft Visual Studio 2010 SDK\VisualStudioIntegration\Common\Assemblies\v4.0和%ProgramFiles%Microsoft Visual Studio 2010 SDK\VisualStudioIntegration\Common\Assemblies\v2.0。

  添加了相应的程序集引用,并将BaseCodeGeneratorWithSite这个抽象类作为MessageCodeGenerator的基类后,需要实现如下两个抽象方法:GenerateCode和GetDefaultExtension。

namespace Artech.CodeDomGenerator  
{      
    
public class MessageCodeGenerator : BaseCodeGeneratorWithSite  
     {        
        
public CodeCompileUnit BuildCodeObject(XmlDocument messages)  
         {  
            
//......  
         }                
         protected override
byte[] GenerateCode(string inputFileName, string inputFileContent)  
         {  
            var messageDoc
= new XmlDocument();  
             messageDoc.LoadXml(inputFileContent);  
             var codeObject
= BuildCodeObject(messageDoc);  
             CodeDomProvider provider
= CodeDomProvider.CreateProvider("CSharp");  
             CodeGeneratorOptions options
= new CodeGeneratorOptions();  
             options.BracingStyle
= "C";  
             using (StringWriter writer
= new StringWriter())  
             {                
                 provider.GenerateCodeFromCompileUnit(codeObject, writer, options);                  
string code = writer.ToString();  
                
byte[] preambleBytes = Encoding.Unicode.GetPreamble();  
                
byte[] codeBytes = Encoding.Unicode.GetBytes(code);  
                
byte[] result = new byte[preambleBytes.Length + codeBytes.Length];  
                 Buffer.BlockCopy(preambleBytes,
0, result, 0, preambleBytes.Length);  
                 Buffer.BlockCopy(codeBytes,
0, result, preambleBytes.Length, codeBytes.Length);  
                 return result;  
             }  
         }  
    
        
public override string GetDefaultExtension()  
         {  
             return
".cs";  
         }  
     }  
}

 

  GenerateCode返回的字节数组表示最终生成的的代码的内容,在这里的逻辑很简单,就是通过CodeDomProvider将CodeCompileUnit转化成基于具体编程语言(在这里我们只考虑C#)的代码。而GetDefaultExtension返回生成的代码文件的扩展名,在这里自然是“.cs”。 

0
相关文章