自动生成属性






4.83/5 (15投票s)
2005年1月7日
2分钟阅读

124614

1459
一个用于 Visual Studio 的插件,可以自动生成属性。
引言
.NET 引入了面向对象编程,这就是它变得如此流行的原因。 面向对象编程概念之一是封装。 它带来了干净的代码,并且是最好的。 但是,一旦您定义了私有成员,您就必须花费大量时间来编写相应的属性。 我认为加速这个过程并自动生成这些属性会很有趣。 我做了一些研究,在这里找到了一些可以解决问题的宏。 但是,我认为它不是很高效,并且我认为右键单击属性会更容易。 所以我转向 Visual Studio 插件...
背景
为了开发一些插件,Visual Studio 允许我们使用向导,这使得任务更容易。 但它并不像它应该的那样简单,特别是当你想添加一些功能,比如上下文弹出菜单。 我发现了几篇关于这个主题的文章,但每一篇都得出结论,MSDN 在这个主题上并不那么完整,主要是因为它与 Office 相关联。
使用代码
源文件包含两个项目,一个用于插件,一个用于安装程序。 为了正确安装插件,您必须通过安装程序,或者您可以创建一个 *.reg 文件来注册它。 最简单的方法是使用安装程序。 当我在 Visual Studio .NET 2003 上工作时,我不知道它是否适用于 Visual Studio .NET 2002,但我认为它可以。 这是创建按钮的 OnConnection
方法
public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst,
ref System.Array custom)
{
applicationObject = (_DTE)application;
addInInstance = (AddIn)addInInst;
if(connectMode == Extensibility.ext_ConnectMode.ext_cm_Startup)
{
object []contextGUIDS = new object[] { };
Commands commands = applicationObject.Commands;
_CommandBars commandBars = applicationObject.CommandBars;
// When run, the Add-in wizard prepared the registry
// for the Add-in.
// At a later time, the Add-in or its commands may
// become unavailable for reasons such as:
// 1) You moved this project to a computer other
// than which is was originally created on.
// 2) You chose 'Yes' when presented with a message
// asking if you wish to remove the Add-in.
// 3) You add new commands or modify commands
// already defined.
// You will need to re-register the Add-in by building
// the PropertyGeneratorSetup project,
// right-clicking the project in the Solution Explorer,
// and then choosing install.
// Alternatively, you could execute the ReCreateCommands.reg
// file the Add-in Wizard generated in
// the project directory, or run 'devenv /setup' from a command prompt.
try
{
// Fetch parameters from registry
prefix = Helper.GetRegistryValue(Helper.OPTION_PREFIX,
Helper.DEFAULT_PREFIX);
getterSetterComment =
Helper.GetRegistryValue(Helper.OPTION_GETTERSETTER_COMMENT,
Helper.DEFAULT_GETTERSETTER_COMMENT);
getterComment =
Helper.GetRegistryValue(Helper.OPTION_GETTER_COMMENT,
Helper.DEFAULT_GETTER_COMMENT);
setterComment =
Helper.GetRegistryValue(Helper.OPTION_SETTER_COMMENT,
Helper.DEFAULT_SETTER_COMMENT);
popupMenuEnabled =
Boolean.Parse(Helper.GetRegistryValue(Helper.OPTION_POPUPMENU,
Helper.DEFAULT_POPUPMENU));
// Declare the commandBar which will hosts commands
CommandBar cmbHost;
// Fetch contextual menu from code editor
CommandBar cmbCodeWindow = (CommandBar)commandBars["Code Window"];
// Define commands text
string libGetterSetter = "getter / setter";
string libGetter = "getter";
string libSetter = "setter";
if (popupMenuEnabled)
{
// In case of a popup menu, we have to add an invisible command
// to force QueryStatus function to be called when
// the user right clicks
Command cmdEnabler = commands.AddNamedCommand(addInInstance,
"PropertyGeneratorEnabler",
"",
"",
true,
0,
ref contextGUIDS,
(int)vsCommandStatus.vsCommandStatusInvisible);
cmdEnabler.AddControl(cmbCodeWindow, 1);
// Create the popup menu
CommandBarPopup cbcPropertyGenerator = (CommandBarPopup)
cmbCodeWindow.Controls.Add(MsoControlType.msoControlPopup,
Missing.Value,
Missing.Value,
1,
true);
cbcPropertyGenerator.Visible = true;
cbcPropertyGenerator.BeginGroup = true;
cbcPropertyGenerator.Caption = "Generate property for...";
// Get the associated commandBar to add commands
cmbPropertyGenerator = cbcPropertyGenerator.CommandBar;
// Copy reference
cmbHost = cmbPropertyGenerator;
}
else
{
libGetterSetter = libGetterSetter + "Generate property for ";
libGetter = libGetter + "Generate property for ";
libSetter = libSetter + "Generate property for ";
cmbHost = cmbCodeWindow;
}
// Add Getter, Setter and Getter/Setter commands
Command cmdGetterSetter = commands.AddNamedCommand(addInInstance,
"PropertyGeneratorGetterSetter",
libGetterSetter,
"Generate property for Getter/Setter",
true,
6948,
ref contextGUIDS,
(int)vsCommandStatus.vsCommandStatusSupported +
(int)vsCommandStatus.vsCommandStatusEnabled);
cmdGetterSetter.AddControl(cmbHost, 1);
Command cmdGetter = commands.AddNamedCommand( addInInstance,
"PropertyGeneratorGetter",
libGetter,
"Generate property for Getter",
true,
6947,
ref contextGUIDS,
(int)vsCommandStatus.vsCommandStatusSupported+
(int)vsCommandStatus.vsCommandStatusEnabled);
cmdGetter.AddControl(cmbHost, 2);
Command cmdSetter = commands.AddNamedCommand(addInInstance,
"PropertyGeneratorSetter",
libSetter,
"Generate property for Setter",
true,
6943,
ref contextGUIDS,
(int)vsCommandStatus.vsCommandStatusSupported+
(int)vsCommandStatus.vsCommandStatusEnabled);
cmdSetter.AddControl(cmbHost, 3);
}
catch(System.Exception e)
{
// Delete existing commands
foreach(Command cmd in commands)
{
if ((cmd.Name != null) &&
(cmd.Name.StartsWith("PropertyGenerator")))
cmd.Delete();
}
// Show the message error
MessageBox.Show("An error ocurred : " +
e.Message + "\r\n\nPropertyGenerator "+
"has been cleaned. Please restart Visual Studio",
"PropertyGenerator error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
PropertyGenerator 在 Visual Studio 启动时创建按钮,并在 Visual Studio 停止时删除它们。 这样比在安装程序上创建它们更容易控制插件。
这是生成属性的代码
private void GenerateProperty(PropertyTypeValue propertyType)
{
string propType = "";
string propName = "";
string propVariable = "";
string prop = "";
try
{
// Fetch informations to generate the property
FormatParameters(prefix, ref propType,
ref propName, ref propVariable);
// Get current selection
TextSelection txsSelection =
(TextSelection)applicationObject.ActiveDocument.Selection;
// Go to the end of line
txsSelection.EndOfLine(false);
// Jump 2 lines
txsSelection.NewLine(2);
// Generate property
switch(propertyType)
{
case PropertyTypeValue.GetterSetter :
prop = String.Concat( "/// <SUMMARY>\r\n/// ",
getterSetterComment,
" \r\n/// </SUMMARY>\r\npublic ",
propType,
" ",
propName,
" {\r\nget\r\n{\r\nreturn ",
propVariable,
";\r\n}\r\nset\r\n{\r\n",
propVariable,
" = value;\r\n}\r\n}");
break;
case PropertyTypeValue.Getter :
prop = String.Concat( "/// <SUMMARY>\r\n/// ",
getterComment,
" \r\n/// </SUMMARY>\r\npublic ",
propType,
" ",
propName,
" {\r\nget\r\n{\r\nreturn ",
propVariable,
";\r\n}\r\n}");
break;
case PropertyTypeValue.Setter :
prop = String.Concat( "/// <SUMMARY>\r\n/// ",
setterComment,
" \r\n/// </SUMMARY>\r\npublic ",
propType,
" ",
propName,
" {\r\nset\r\n{\r\n",
propVariable,
" = value;\r\n}\r\n}");
break;
}
// Insert into the code
txsSelection.Insert(prop,
(int)vsInsertFlags.vsInsertFlagsInsertAtEnd);
// Go to the start of line
txsSelection.StartOfLine(
vsStartOfLineOptions.vsStartOfLineOptionsFirstText, true);
// Format code
txsSelection.SmartFormat();
// Go to the end of comment
txsSelection.GotoLine(txsSelection.TopPoint.Line + 1, false);
txsSelection.EndOfLine(false);
}
catch(Exception)
{
throw;
}
}
我做了一个选项卡来设置一些参数
它们存储在注册表中,这就是为什么您必须使用安装程序来创建有用的键。 您可以参数化前缀、自动注释,并且您可以选择是否在弹出菜单中显示按钮。 要添加选项卡,您必须创建一个实现 IDTToolsOptionsPage
接口的 UserControl
类。
关注点
我希望这个小插件能帮助一些人。 我相信这里有一些有趣的概念,比如选项卡弹出菜单
历史
- 2005/01/07 - 版本 1.0.0
- 2005/02/09 - 版本 1.1.0
- 属性生成的主要错误更正。
- 上下文标签更正。
- 前缀大小优化(感谢 Olivier)。
- 2005/02/09 - 版本 1.2.0
- 没有可见性的成员的错误更正(由 vasiletomoiaga 发现)。
- 2005/02/11 - 版本 1.3.0
- 选项卡中的错误(由 Stefan 发现)。
- 2005/04/26 - 版本 1.4.0
- 使用成员的摘要作为属性的注释(感谢 Bjørnar Sundsbø)。