实现自定义的VsSingleFileGenerator

         用过VS.NET的朋友应该会发现,在编辑一些文件时VS会在文件下面自动创建它的附属文件.而这些附属文件往往是根据设计文件生成的代码文件来的.对于我们想实现这样的功能怎办呢?其实MS早就为我们想好了,只要简单地实现IVsSingleFileGenerator;说是简单不过还是要做些功夫的,就是把编写后VsSingleFileGenerator注册到共公程序集中,然后在注册表里添加一些东西才行.下面介绍自己实现NClay实体设计的SingleFileGenerator,有需要的朋友可以参考代码实现自己的SingleFileGenerator:)

实现目的编写XML模型描述后自动生成附属C#代码文件.

XML设计文件:

<?xml version="1.0" encoding="utf-8" ?>

<nclay_models xmlns="http://nclay.cn/model.xsd" namespace="Blogs.Entities">

  <class name="User" table="TUser" comment="">

    <id name="UserID" type="System.String"/>

    <property name="UserName" type="System.String"/>

    <property name="UserPWD" type="System.String"/>

    <property name="EMail" type="System.String"/>

    <property name="Enabled" type="System.String"/>

    <property name ="Remark" type="System.String"/>

  </class>

</nclay_models>

生成代码模型文件内容:

using System;
    
using System.Data;
    
using NClay.Data;
    
using NClay.Data.Mappings;
    
    
    [TableMapper(Name
="User")]
    
public partial class User {
        
        
private void mUserID;
        
        [PrimaryKey(Name
="UserID")]
        
public virtual void UserID {
            
get {
                
return this.mUserID;
            }

            
set {
                
this.mUserID = value;
            }

        }

        
        
public partial class Mapper : Table {
            
            
private ObjectField mAll;
            
            
private ObjectField mUserID;
            
            
public Mapper() : 
                    
base("User"{
                
this.mAll = new ObjectField("*"this);
                
this.mUserID = new ObjectField("UserID"this);
            }

            
            
public virtual ObjectField All {
                
get {
                    
return this.mAll;
                }

            }

            
            
public virtual ObjectField UserID {
                
get {
                    
return this.mUserID;
                }

            }

        }

    }

    
    
public partial class ModelContext {
        
        
static User.Mapper mUser = new User.Mapper();
        
        
public static User.Mapper User {
            
get {
                
return mUser;
            }

        }

    }

对于SingleFileGenerator的编写我直接就贴代码,其实也没什么好讲就一个类.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell.Interop;
using System.ComponentModel;
using System.CodeDom.Compiler;
using Microsoft.VisualStudio.Shell;
using VSOLE = Microsoft.VisualStudio.OLE.Interop;
using System.CodeDom;
using System.IO;
using System.Xml;

namespace NClay.Generators
{
  

    [Guid(
"2F6150C6-BC48-4733-96FE-91F2A90AADCF")]
    
public class ModelGenerator : IVsSingleFileGenerator, VSOLE::IObjectWithSite
    
{
        
private CodeDomProvider codeProvider;

        
private string codeFileNameSpace;
        
private string codeFilePath;

        
private object site;

        
private IVsGeneratorProgress codeGeneratorProgress;

        
public CodeDomProvider CodeProvider
        
{
            
get
            
{
                
if (this.codeProvider == null)
                
{
                    codeProvider 
= CodeDomProvider.CreateProvider("C#");
                }


                
return this.codeProvider;
            }


            
set
            
{
                
if (value == null)
                
{
                    
throw new ArgumentNullException();
                }


                
this.codeProvider = value;
            }

        }


        
IVsSingleFileGenerator Members

        
IObjectWithSite Members

        
Private Methods
    }


    
class CodeGenerator
    
{
        
public static CodeCompileUnit GeneratorByCodeDom(XmlDocument doc, CodeDomProvider codeprovider)
        
{
            CodeCompileUnit codeunit 
= new CodeCompileUnit();
            CodeNamespace nspace 
= null;
            
try
            
{
                nspace 
= new CodeNamespace(
                     doc.ChildNodes[
1].Attributes["namespace"].Value);
                codeunit.Namespaces.Add(nspace);
                nspace.Imports.Add(
new CodeNamespaceImport("System"));
                nspace.Imports.Add(
new CodeNamespaceImport("System.Data"));
                nspace.Imports.Add(
new CodeNamespaceImport("NClay.Data"));
                nspace.Imports.Add(
new CodeNamespaceImport("NClay.Data.Mappings"));
                
foreach (XmlNode cls in doc.ChildNodes[1].ChildNodes)
                
{
                    
if (cls.Name.ToLower() == "class")
                        CreateClass(nspace, cls);
                }



            }

            
catch (Exception e_)
            
{
                nspace.Comments.Add(
new CodeCommentStatement(e_.Message));
            }

            
return codeunit;
        }

        
private static void CreateClass(CodeNamespace nspace, XmlNode cls)
        
{
            CodeMemberField mfield;
            CodeMemberProperty mproperty;
            
string type, name, column, table, sequence, cast, comment;
            comment 
= null;
            sequence 
= null;
            cast 
= null;
            name 
= cls.Attributes["name"].Value;
            
if (cls.Attributes["table"== null)
                table 
= name;
            
else
                table 
= cls.Attributes["table"].Value;
            
if (cls.Attributes["comment"!= null)
                comment 
= cls.Attributes["comment"].Value;
            name 
= FirstToUpper(name);
            table 
= FirstToUpper(table);
            CodeTypeDeclaration entity 
= new CodeTypeDeclaration(
                name);
            entity.CustomAttributes.Add(
new CodeAttributeDeclaration(new CodeTypeReference("TableMapper"),
                
new CodeAttributeArgument("Name"new CodePrimitiveExpression(table))));
            entity.IsPartial 
= true;
            
if (comment != null)
            
{
                entity.Comments.Add(
new CodeCommentStatement("<summary>"true));
                entity.Comments.Add(
new CodeCommentStatement(comment, true));
                entity.Comments.Add(
new CodeCommentStatement("</summary>"true));
            }

            CodeTypeDeclaration mapper 
= new CodeTypeDeclaration("Mapper");
            mapper.IsPartial 
= true;
            mapper.BaseTypes.Add(
new CodeTypeReference("Table"));
            entity.Members.Add(mapper);
            
if (comment != null)
            
{
                mapper.Comments.Add(
new CodeCommentStatement("<summary>"true));
                mapper.Comments.Add(
new CodeCommentStatement(comment, true));
                mapper.Comments.Add(
new CodeCommentStatement("</summary>"true));
            }

            CodeConstructor constructor 
= new CodeConstructor();
            constructor.Attributes 
= MemberAttributes.Public;
            constructor.BaseConstructorArgs.Add(
new CodePrimitiveExpression(table));
            mapper.Members.Add(constructor);
            mfield 
= new CodeMemberField(new CodeTypeReference("ObjectField"), "mAll");
            mapper.Members.Add(mfield);
            mproperty 
= new CodeMemberProperty();
            mproperty.Type 
= new CodeTypeReference("ObjectField");
            mproperty.Name 
= "All";
            mproperty.Attributes 
= MemberAttributes.Public;
            mproperty.GetStatements.Add(
new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "mAll")));
            mapper.Members.Add(mproperty);
            CodeAssignStatement assingexp;
            assingexp 
= new CodeAssignStatement(
                
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "mAll"),
                
new CodeObjectCreateExpression("ObjectField",
                    
new CodePrimitiveExpression("*"),
                    
new CodeThisReferenceExpression()));
            constructor.Statements.Add(assingexp);

            comment 
= null;
            
foreach (XmlNode property in cls.ChildNodes)
            
{
                
entity
                
string mapptype;
                
mapper


            }



            nspace.Types.Add(entity);
            name 
= cls.Attributes["name"].Value;
            name 
= FirstToUpper(name);
            CodeTypeDeclaration modelcontext 
= new CodeTypeDeclaration("ModelContext");
            modelcontext.IsPartial 
= true;
            mfield 
= new CodeMemberField(new CodeTypeReference(name + ".Mapper"), "m" + name);
            mfield.Attributes 
= MemberAttributes.Static;
            mfield.InitExpression 
= new CodeObjectCreateExpression(new CodeTypeReference(name + ".Mapper"), new CodeExpression[] { });
            modelcontext.Members.Add(mfield);
            mproperty 
= new CodeMemberProperty();
            mproperty.Type 
= new CodeTypeReference(name + ".Mapper");
            mproperty.Name 
= name;
            mproperty.Attributes 
= MemberAttributes.Public | MemberAttributes.Static;
            mproperty.GetStatements.Add(
new CodeMethodReturnStatement(new CodeVariableReferenceExpression("m" + name)));
            modelcontext.Members.Add(mproperty);

            nspace.Types.Add(modelcontext);
        }

        
private static string FirstToUpper(string value)
        
{
            
string first = value.Substring(01).ToUpper();
            
return first + value.Substring(1, value.Length - 1);
        }


    }

}

接下来就是注册

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\CLSID\{2F6150C6-BC48-4733-96FE-91F2A90AADCF}]

@="NClay.Generators.ModelGenerator"

"InprocServer32"="d:\\windows\\system32\\mscoree.dll"

"Class"="NClay.Generators.ModelGenerator"

"Assembly"="NClay.Generators, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8c768ba656ce9125"

"ThreadingModel"="Both"

 

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{164B10B9-B200-11D0-8C61-00A0C91E29D5}\NClayGenerator]

@="NClay Model Generator"

"CLSID"="{2F6150C6-BC48-4733-96FE-91F2A90AADCF}"

"GeneratesDesignTimeSource"=dword:00000001

 

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{E6FDF8B0-F3D1-11D4-8576-0002A516ECE8}\NClayGenerator]

@="NClay Model Generator"

"CLSID"="{2F6150C6-BC48-4733-96FE-91F2A90AADCF}"

"GeneratesDesignTimeSource"=dword:00000001

 

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}\NClayGenerator]

@="NClay Model Generator"

"CLSID"="{2F6150C6-BC48-4733-96FE-91F2A90AADCF}"

"GeneratesDesignTimeSource"=dword:00000001

所有CLSID对应的值是实现IVsSingleFileGeneratorGuid描述.(记住要所DLL注册到全局程序集中)

这样SingleFileGenerator就完成了,VS中使用这个SingleFileGenerator.在解决方案管理器右键文件属性,在自定义工具填写上: NclayGenerator

在这个应用中也许有朋友想这样编写XML很麻烦,又没有编写提示和验证等功能.其实MS也为我们想好了,只需要写个XmlSchema就可以了.下载代码里也有考参文件.

 

 

下载代码

参考资料:

其实在google 搜一下IVsSingleFileGenerator就有一堆资料

多谢timiil告诉我IVsSingleFileGenerator的功能.

posted on 2008-06-11 20:59  henry  阅读(2502)  评论(6编辑  收藏  举报

导航