通过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,后面的两个命令即是在这两种方式间进行转换。

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

 

复制代码
ExpandedBlockStart.gif 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)命令的实现

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

复制代码
ExpandedBlockStart.gif 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时,可以采用正则表达式找出选中行中的多个字段,为它们一一生成属性,最后将属性代码放入剪贴板:

ContractedBlock.gif C# Code - 实现BatchProperty命令


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

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


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

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


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

复制代码
ExpandedBlockStart.gif 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时,思路与上面相同,也是将查找到的各个常规属性转换为自动属性:

ContractedBlock.gif 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

复制代码
ExpandedBlockStart.gif 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,如需转载请自行联系原作者。

目录
相关文章
|
6天前
|
前端开发
Antd中Table列表行默认包含修改及删除功能的封装
Antd中Table列表行默认包含修改及删除功能的封装
51 0
|
6天前
|
编译器
【【C++11特性篇】【强制/禁止 】生成默认函数的关键字default&delete(代码演示)
【【C++11特性篇】【强制/禁止 】生成默认函数的关键字default&delete(代码演示)
|
6天前
|
JavaScript 前端开发 算法
< 封装公共导出模块:配合element实现提示 >
在 Vue + elementUi 开发中,我们偶尔会遇到需要导出的列表,或者指定位置的导出内容。在一个项目里面是十分常见的,但是由于导出代码有稍微有点长,不方便维护!基于项目开发需求,封装了一个公用的导出模块,模块入口提供了 四个参数,分别是:导出接口地址导出参数对象导出文件名称导出时选择的服务地址(需要配合config文件实现选择功能)。且基于信息安全问题,实现信息提示,当提示点击遵守规则才允许下载文件!
< 封装公共导出模块:配合element实现提示 >
|
9月前
|
容器
【C++11】 统一的列表初始化( {}初始化 )
c++11为了统一初始化方式引入了列表初始化方式,也就是使用{}对变量或者结构体变量等进行初始化。本文会以简单的语言介绍c++11的列表初始化方式和std::initializer_list。
|
7月前
|
算法 Swift
21 Set的定义和创建
Set的定义和创建
85 0
|
8月前
|
Web App开发 API 开发者
关于 SAP UI5 Context.prototype.delete 方法的输入参数 Group ID 的细节
关于 SAP UI5 Context.prototype.delete 方法的输入参数 Group ID 的细节
64 0
es6删除对象的某个属性
1.不改变原始对象 方法1(删除age属性为例) 方法2(删除age为例) 2 delete删除,改变原有数组 删除age属性为例
403 0
es6删除对象的某个属性
X11/XWindow更改属性代码
X11/XWindow更改属性代码
78 0
|
分布式计算 大数据 API
Column 对象_创建_有绑定| 学习笔记
快速学习 Column 对象_创建_有绑定
61 0
 Column 对象_创建_有绑定| 学习笔记
|
存储 程序员 编译器
c++11标准 类默认函数的控制:"=default" 和 "=delete"函数
c++11标准 类默认函数的控制:"=default" 和 "=delete"函数
130 0