通过PropertyManager Add-In管理代码中的属性
2009-04-01 22:05 Anders Cui 阅读(3917) 评论(6) 编辑 收藏 举报前言
在可扩展性开发(七)中,我介绍了如何对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)添加命令
按上面的分析,这里需要三个命令,界面看起来像这样:
Batch Property为选中的多个字段生成属性代码。这里将原有的传统的声明方式称为Normal-Property,将自动属性称为Auto-Property,后面的两个命令即是在这两种方式间进行转换。
使用下面的代码添加命令:

CommandBar codeWinCommandBar = helper.GetCommandBarByName("Code Window");
int pmPopupIndex = codeWinCommandBar.Controls.Count + 1;
CommandBarPopup pmPopup = codeWinCommandBar.Controls.Add(
MsoControlType.msoControlPopup, Type.Missing, Type.Missing,
pmPopupIndex, true) as 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)命令的实现
为简化问题,这里约定字段、自动属性和常规属性的声明格式为:

private int id;
string name;
private DateTime birth;
private int Id { get; set; }
public string Name { private get; set; }
public DateTime Birth { get; private 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时,可以采用正则表达式找出选中行中的多个字段,为它们一一生成属性,最后将属性代码放入剪贴板:

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

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

private int id;
string name;
private readonly DateTime birth;
会生成如下的代码(会拷贝到剪贴板中):

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

对于代码
{
get { return id; }
set { id = value; }
}
public string Name
{
set { name = value; }
}
public DateTime Birth
{
get { return birth; }
}
生成的结果为:
public string Name { private get; set; }
public DateTime Birth { get; private set; }
最后是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://anderslly.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异