用过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#region IVsSingleFileGenerator Members

public int DefaultExtension(out string ext)

{
string defExt;
ext = string.Empty;

defExt = this.CodeProvider.FileExtension;

if (((defExt != null) && (defExt.Length > 0)) && (defExt[0] != '.'))

{
defExt = "." + defExt;
}

if (!string.IsNullOrEmpty(defExt))

{
ext = ".NCaly" + defExt;
}

return 0;
}

public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] pbstrOutputFileContents, out uint pbstrOutputFileContentSize, IVsGeneratorProgress pGenerateProgress)

{
if (bstrInputFileContents == null)

{
throw new ArgumentNullException(bstrInputFileContents);
}

this.codeFilePath = wszInputFilePath;
this.codeFileNameSpace = wszDefaultNamespace;
this.codeGeneratorProgress = pGenerateProgress;

byte[] generatedStuff = this.GenerateCode(wszInputFilePath, bstrInputFileContents);

if (generatedStuff == null)

{
pbstrOutputFileContents[0] = IntPtr.Zero;
pbstrOutputFileContentSize = 0;
}
else

{
pbstrOutputFileContents[0] = Marshal.AllocCoTaskMem(generatedStuff.Length);
Marshal.Copy(generatedStuff, 0, pbstrOutputFileContents[0], generatedStuff.Length);
pbstrOutputFileContentSize = (uint)generatedStuff.Length;
}
return 0;
}
#endregion


IObjectWithSite Members#region IObjectWithSite Members

public void GetSite(ref Guid riid, out IntPtr ppvSite)

{
if (this.site == null)

{
throw new Win32Exception(-2147467259);
}

IntPtr objectPointer = Marshal.GetIUnknownForObject(this.site);

try

{
Marshal.QueryInterface(objectPointer, ref riid, out ppvSite);
if (ppvSite == IntPtr.Zero)

{
throw new Win32Exception(-2147467262);
}
}
finally

{
if (objectPointer != IntPtr.Zero)

{
Marshal.Release(objectPointer);
objectPointer = IntPtr.Zero;
}
}
}

public void SetSite(object pUnkSite)

{
this.site = pUnkSite;
this.codeProvider = null;
}

#endregion


Private Methods#region Private Methods
protected byte[] GenerateCode(string inputFileName, string inputFileContent)

{
CodeCompileUnit compileUnit;

StreamWriter writer = new StreamWriter(new MemoryStream(), Encoding.UTF8);

XmlDocument doc = new XmlDocument();
doc.LoadXml(inputFileContent);

//compileUnit = ClassGenerator.Create(doc, this.codeProvider);
//补上代码
compileUnit = CodeGenerator.GeneratorByCodeDom(doc, this.CodeProvider);

if (this.codeGeneratorProgress != null)

{
this.codeGeneratorProgress.Progress(