Visual Studio 核心代码模型(Addin+CodeModel)使用心得 .

 

我们知道Visual Studio 2010的UML设计功能已经可以做到正向工程了,但是这些生成的代码都是空架子,还得经过手工处理填充上业务逻辑代码,如果系统是基于某个具体技术框架进行开发的话,还必须加上这些技术框架的特性代码。比如:

  /// <summary>
  /// 布尔值选项
  /// </summary>
  [Serializable]
  public enum BooleanOption
  {
    /// <summary>
    /// 否
    /// </summary>
    [EnumCaption("否")]
    N,

    /// <summary>
    /// 是
    /// </summary>
    [EnumCaption("是")]
    Y
  }

代码里面的[Serializable]、[EnumCaption("否")]都是需要附加到代码里的。

为了实现快速开发,减少开发工作量,这些工作是否可以让机器代劳?利用“Visual Studio 自动化对象模型”技术似乎是个可行方案。

http://msdn.microsoft.com/zh-cn/library/za2b25t3(v=VS.80).aspx

只要我们在VS的IDE里利用Addin插件技术,参与到它的代码编辑功能中,通过分析类的定义,将技术框架的特征码嵌入到代码文本中。

基于上述的想法,我们开始探索之旅:

1,在代码编辑窗体的弹出菜单里嵌入一个菜单项,借此触发实现我们的需求:

    基于网上有很多编写Connect类的介绍,本文不再多说,代码节选如下:

    /// <summary>实现 IDTExtensibility2 接口的 OnConnection 方法。接收正在加载外接程序的通知。</summary>
    /// <param term='application'>宿主应用程序的根对象。</param>
    /// <param term='connectMode'>描述外接程序的加载方式。</param>
    /// <param term='addInInst'>表示此外接程序的对象。</param>
    /// <seealso class='IDTExtensibility2' />
    public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
    {
      _applicationObject = (DTE2)Application;
      _addInInstance = (AddIn)AddInInst;

      //如果是安装状态或是插件刚被启动的状态,则创建菜单
      if (ConnectMode == Extensibility.ext_ConnectMode.ext_cm_UISetup
        || ConnectMode == Extensibility.ext_ConnectMode.ext_cm_Startup)
      {
        //取代码编辑窗口右键弹出菜单的工具条
        CommandBar codeWindowBar = ((CommandBars)_applicationObject.CommandBars)["Code Window"];
        //将菜单项加入工具条
        object[] contextGUIDS = new object[] { };
        Command commandObj = _applicationObject.Commands.AddNamedCommand(_addInInstance,
          _buildClassMenuName, "构建业务类/规则类", "业务类由指定的数据库表/视图映射",
          true, 137, ref contextGUIDS,
          (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled
        );
        commandObj.AddControl(codeWindowBar);
      }
    }

2,通过当前活动的编辑窗体ActiveDocument找到它的工程项ProjectItem,通过工程项得到我们需要的FileCodeModel:

    FileCodeModel2 codeModel = (FileCodeModel2)_applicationObject.ActiveDocument.ProjectItem.FileCodeModel;

我们知道FileCodeModel是操作代码模型的入口:

http://msdn.microsoft.com/zh-cn/library/envdte.filecodemodel.aspx

3,通过FileCodeModel,我们可以对当前代码编辑框内的代码进行改写了,但是首先要找到改写的点,由于FileCodeModel是一个树,我们要遍历它,为了方便遍历,写了这样的公共函数:

internal static class CodeModelHelper
  {
    public static List<CodeElement2> FindAllCodeElement(CodeElements elements, vsCMElement kind)
    {
      List<CodeElement2> result = new List<CodeElement2>();
      FindAllCodeElement(elements, kind, ref result);
      return result;
    }

    private static void FindAllCodeElement(CodeElements elements, vsCMElement kind, ref List<CodeElement2> elementList)
    {
      if (elements != null)
        foreach (CodeElement2 item in elements)
        {
          if (item.Kind == kind)
            elementList.Add(item);
          FindAllCodeElement(item.Children, kind, ref elementList);
        }
    }
  }

我们要找到这个代码文本中所有的枚举定义,应该这么做:

CodeModelHelper.FindAllCodeElement(codeModel.CodeElements, vsCMElement.vsCMElementEnum)

返回的是符合vsCMElement.vsCMElementEnum条件的CodeElement的集合,我们遍历这个集合,可以将把[Serializable]添加到枚举上:

public void Exec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
    {
      if (ExecuteOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
      {
        if (CmdName == _buildClassCmdName)
        {
           FileCodeModel2 codeModel = (FileCodeModel2)_applicationObject.ActiveDocument.ProjectItem.FileCodeModel;
           ExecuteBuildEnumClass(CodeModelHelper.FindAllCodeElement(codeModel.CodeElements, vsCMElement.vsCMElementEnum));
          Handled = true;
          return;
        }
      }
      Handled = false;
    }

private static void ExecuteBuildEnumClass(List<CodeElement2> elementList)
    {
      foreach (CodeEnum item in elementList)
      {
        item.AddAttribute(typeof(SerializableAttribute).Name, null);
      }
    }

结论:

上述简单地演示了一个通过Addin插件来有针对性地批量修改代码的方法,在此基础上,我们可以做很多有趣的事情,但是目的是一个,就是尽可能偷懒,即加快我们开发又不出错。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值