通过PropertyManager Add-In管理代码中的属性

简介:

前言

可扩展性开发(七)中,我介绍了如何对VS中的编辑器进行操作。在CodeTemplate例子中可以看到,大部分的工作量不是在编辑器的操作上,而是在于相关功能的逻辑处理上。本文将介绍另一个与编辑器相关的例子PropertyManager。

问题分析

PropertyManager用来管理代码中的属性。我们在C# 3.0之前编写代码时,与属性相关的主要操作是将字段封装为属性,VS 2005中的Refactor->Encapsulate Field菜单(快捷键Ctrl+R, E)可以简化这个操作。它每次封装一个字段,并将生成的属性放在字段所在行的下一行,但是大部分人的编码习惯是将字段放在一起,将属性们放在一起,所以首先PropertyManager要做到这一点。

C#3.0引入了自动属性的特性,使得我们在处理简单属性的时候更为简单。但是我们有时候还是需要使用传统风格的属性声明方式,PropertyManager还要能在这两种声明方式之间进行转化。(这个需求来自于园子里的Clingingboy

下面就来看看如何在Add-In中实现这些功能。

实现PropertyManager

1)添加命令

按上面的分析,这里需要三个命令,界面看起来像这样:

property-manager-menu

Batch Property为选中的多个字段生成属性代码。这里将原有的传统的声明方式称为Normal-Property,将自动属性称为Auto-Property,后面的两个命令即是在这两种方式间进行转换。

使用下面的代码添加命令:

 

复制代码
C# Code - 添加ProjectManager命令
CommandBar codeWinCommandBar = helper.GetCommandBarByName("Code Window");

int pmPopupIndex = codeWinCommandBar.Controls.Count + 1;
CommandBarPopup pmPopup 
= codeWinCommandBar.Controls.Add(
    MsoControlType.msoControlPopup, Type.Missing, Type.Missing,
    pmPopupIndex, 
trueas CommandBarPopup;
pmPopup.Caption 
= "PropertyManager";

CommandBarButton batchPropertyCmd 
= helper.AddButtonToPopup(pmPopup, pmPopup.Controls.Count + 1,
    
"Batch Property""Encapsulate these fields");
batchPropertyCmdEvent 
= _applicationObject.Events.get_CommandBarEvents(batchPropertyCmd) as CommandBarEvents;
batchPropertyCmdEvent.Click 
+= new _dispCommandBarControlEvents_ClickEventHandler(BatchPropertyCmdEvent_Click);

CommandBarButton convertToAutoPropCmd 
= helper.AddButtonToPopup(pmPopup, pmPopup.Controls.Count + 1,
    
"Convert to Auto-Property""Convert to Auto-Property(C# 3.0 style)");
convertToAutoPropCmdEvent 
= _applicationObject.Events.get_CommandBarEvents(convertToAutoPropCmd) as CommandBarEvents;
convertToAutoPropCmdEvent.Click 
+= new _dispCommandBarControlEvents_ClickEventHandler(ConvertToAutoPropCmdEvent_Click);

CommandBarButton convertToNormalPropCmd 
= helper.AddButtonToPopup(pmPopup, pmPopup.Controls.Count + 1,
    
"Convert to Normal-Property""Convert to Normal-Property(C# 2.0 style)");
convertToNormalPropCmdEvent 
= _applicationObject.Events.get_CommandBarEvents(convertToNormalPropCmd) as CommandBarEvents;
convertToNormalPropCmdEvent.Click 
+= new _dispCommandBarControlEvents_ClickEventHandler(ConvertToNormalPropCmdEvent_Click);
复制代码


2)命令的实现

为简化问题,这里约定字段、自动属性和常规属性的声明格式为:

复制代码
C# Code - 字段和属性约定格式
private int id;
string name;
private DateTime birth;

private int Id { getset; }
public string Name { private getset; }
public DateTime Birth { getprivate set; }

public int Id
{
    
get { return id; }
    
set { id = value; }
}
public string Name
{
    
get { return name; }
    
set { name = value; }
}
public DateTime Birth
{
    
get { return birth; }
    
set { birth = value; }
}
复制代码


字段采用camelCase风格命名,属性采用PascalCase风格命名。

在实现Batch Property时,可以采用正则表达式找出选中行中的多个字段,为它们一一生成属性,最后将属性代码放入剪贴板:

C# Code - 实现BatchProperty命令


GetSelectedLines方法是获取当前文档中选中的代码行:

C# Code - 获取选中的文本行


字段可能为readonly的,此时将只生成getter代码。这样在生成属性时考虑的主要因素为:字段类型、字段名称、是否只读。这样

C# Code
private int id;
string name;
private readonly DateTime birth;


会生成如下的代码(会拷贝到剪贴板中):

复制代码
C# Code
public int Id
{
    
get { return id; }
    
set { id = value; }
}
public string Name
{
    
get { return name; }
    
set { name = value; }
}
public DateTime Birth
{
    
get { return birth; }
}
复制代码


在实现Convert to Auto-Property时,思路与上面相同,也是将查找到的各个常规属性转换为自动属性:

C# Code - 实现Convert to Auto-Property命令


对于代码

复制代码
public   int  Id
{
    
get  {  return  id; }
    
set  { id  =  value; }
}
public   string  Name
{
    
set  { name  =  value; }
}
public  DateTime Birth
{
    
get  {  return  birth; }
}
复制代码


生成的结果为:

public   int  Id {  get set ; }
public   string  Name {  private   get set ; }
public  DateTime Birth {  get private   set ; }


最后是Convert to Normal-Property

复制代码
C# Code - 实现Convert to Normal-Property命令
private void ConvertToNormalPropCmdEvent_Click(object CommandBarControl, ref bool Handled, ref bool CancelDefault)
{
    
string selectedLines = helper.GetSelectedLines();
    Regex propRegex 
= new Regex(
        
"((?<modifier>\\w+)?\\s+)?(?<type>\\w+)\\s+(?<name>\\w+)\\s*{(.|\\n)*?get;(.|\\n)*?set;\\s*}",
        RegexOptions.IgnoreCase 
| RegexOptions.Multiline);
    MatchCollection autoProperties 
= propRegex.Matches(selectedLines);

    StringBuilder normalProps 
= new StringBuilder();
    
foreach (Match prop in autoProperties)
    {
        
string modifier = prop.Groups["modifier"].Value;
        
string type = prop.Groups["type"].Value;
        
string name = prop.Groups["name"].Value;

        
string propText = prop.Value;
        
bool writeOnly = Regex.IsMatch(propText, "private\\s+get;");
        
bool readOnly = Regex.IsMatch(propText, "private\\s+set;");
        
if (writeOnly && readOnly) { break; }

        normalProps.AppendLine(GenerateNormalProperty(modifier, type, name, readOnly, writeOnly));
    }

    Clipboard.SetText(normalProps.ToString());
}
复制代码


至此这三个命令就全部实现了,它们都是将结果放在剪切板中,因为我感觉很难确定出一个合适的位置。

可以从这里下载代码,也可以在这里下载可运行的Add-In(解压缩后将文件放在[My Documents Path]\Visual Studio 2008\Addins下)。

希望这个功能能让您对编辑器的扩展有更多的了解。



本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2009/04/01/vs-addin-property-manager.html,如需转载请自行联系原作者。

目录
相关文章
|
8月前
|
前端开发
Antd中Table列表行默认包含修改及删除功能的封装
Antd中Table列表行默认包含修改及删除功能的封装
189 0
|
3月前
|
监控 JavaScript 开发者
在 Vue 中,子组件为何不可以修改父组件传递的 Prop,如果修改了,Vue 是如何监控到属性的修改并给出警告的
在 Vue 中,子组件不能直接修改父组件传递的 Prop,以确保数据流的单向性和可预测性。如果子组件尝试修改 Prop,Vue 会通过响应式系统检测到这一变化,并在控制台发出警告,提示开发者避免这种操作。
|
6月前
Element UI【实战范例】下拉选择 el-select 的 change 事件传入选中值+自定义参数
Element UI【实战范例】下拉选择 el-select 的 change 事件传入选中值+自定义参数
924 1
|
容器
【C++11】 统一的列表初始化( {}初始化 )
c++11为了统一初始化方式引入了列表初始化方式,也就是使用{}对变量或者结构体变量等进行初始化。本文会以简单的语言介绍c++11的列表初始化方式和std::initializer_list。
182 1
|
移动开发 JSON JavaScript
weex-使用Vue.set设置属性和使用this.xxx设置属性的区别
weex-使用Vue.set设置属性和使用this.xxx设置属性的区别
129 0
weex-使用Vue.set设置属性和使用this.xxx设置属性的区别
|
前端开发 开发者
评论列表案例-将评论 Item 项抽离为单独的 CmtItem 组件|学习笔记
快速学习评论列表案例-将评论 Item 项抽离为单独的 CmtItem 组件
|
JavaScript
JS 高级(四)ES5保护对象、Object.create()、替换this指向
JS 高级(四)ES5保护对象、Object.create()、替换this指向
289 0
JS 高级(四)ES5保护对象、Object.create()、替换this指向
评论列表案例-将评论Item项抽离为单独的CmtItem组件
评论列表案例-将评论Item项抽离为单独的CmtItem组件
|
SQL JSON Oracle
Latke持久层-新增add方法解读
Latke持久层-新增add方法解读
208 0
C++ add()函数的四种实现方式
C++ add()函数的四种实现方式
1166 0

热门文章

最新文章