IDE的宏

 

使用Visual Studio 2005 IDE的宏,自动为c#变量生成属性

<script>init_Nav();</script>

    【IT168技术文档】在编写c#代码过程中,我们经常需要做一些重复枯燥的工作。例如,编写DTO(数据访问对象),通常就是为一个类定义一系列的变量和属性。

    有一些第三方的IDE辅助工具,可以为我们生成一些代码,减少工作量。例如,Assist X就是一款很值得推荐的工具,使用其提供的Encapsulate Field功能,可以很方便地将一个类地编写封装为属性。

    我今天需要介绍的如何使用Visual Studio 2005 IDE中自带的宏实现类似的功能。

    打开Visual Studio 2005 IDE,选择“工具” > "宏" > “宏 IDE”,选择“添加模块”。例如,我是在MyMacros项目中新增了一个EditorHelper模块,代码如下:

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public
 Module EditorHelper
    
'为一个参数封装一般属性访问器

    Public Sub EncapsulateField()
        
Dim projectItem As ProjectItem =
 DTE.ActiveDocument.ProjectItem
        
Dim fileCodeModel As FileCodeModel =
 projectItem.FileCodeModel

        
'得到当前选定的内容

        Dim selectText As TextSelection = DTE.ActiveDocument.Selection
        
'获取到当前光标的位置

        Dim point As TextPoint = selectText.ActivePoint

        Try
            
Dim codeElement As CodeElement =
 fileCodeModel.CodeElementFromPoint(point, vsCMElement.vsCMElementVariable)

            
If (codeElement Is NothingThen

                Return
            
End If

            Debug.Assert(codeElement.Kind 
= vsCMElement.vsCMElementVariable)

            
Dim codeVar As CodeVariable =
 CType(codeElement, CodeVariable)
            
Dim fieldName As String =
 codeVar.Name
            
Dim codeClass As CodeClass =
 CType(codeVar.Parent, CodeClass)

            AddPropertyToClass(codeClass, fieldName, codeVar.Type)
        Catch ex 
As
 Exception
            
'吃掉异常,不做处理或者提示

        End Try

    
End Sub


    
Public Sub EncapsulateAllFields()
        
Dim projectItem As ProjectItem =
 DTE.ActiveDocument.ProjectItem
        
Dim fileCodeModel As FileCodeModel =
 projectItem.FileCodeModel

        Try
            
'得到当前选定的内容

            Dim selectText As TextSelection = DTE.ActiveDocument.Selection
            
'获取到当前光标的位置

            Dim point As TextPoint = selectText.ActivePoint

            
Dim codeElement As CodeElement =
 fileCodeModel.CodeElementFromPoint(point, vsCMElement.vsCMElementClass)
            
Dim codeClass As CodeClass =
 CType(codeElement, CodeClass)

            
Dim i As Integer

            
For i = 1 To codeClass.Members.Count
                
'如果属性已经定义,会抛出异常

                '在这里处理异常,即使新增的属性已经定义,也可以继续处理下面的代码
                Try
                    
Dim element As CodeElement =
 codeClass.Members.Item(i)
                    
If (element.Kind = vsCMElement.vsCMElementVariable) Then

                        
Dim codeVariable As CodeVariable = CType(element, CodeVariable)
                        
If (Not codeVariable.IsShared) Then     '静态变量不需要增加属性

                            AddPropertyToClass(codeClass, codeVariable.Name, codeVariable.Type)
                        
End If

                    
End If
                Catch ex 
As Exception
                    
'吃掉异常

                End Try
            
Next

        Catch ex 
As Exception
            
'可能并没有选择有效的类定义,这时会抛出异常,忽略

        End Try
    
End Sub


    
'根据成员的名称的类型,在类对象中插入属性
    Private Sub AddPropertyToClass(ByVal codeClass As CodeClass, ByVal fieldName As String, ByVal fieldType As Object)
        
'生成属性的名称,规则是首先字母大写。如果变量的开头为“_”,移除

        Dim propertyName As String = fieldName
        
If (propertyName.StartsWith("_")) Then

            propertyName 
= propertyName.TrimStart("_"c)
        
End If

        propertyName 
= propertyName.Substring(01).ToUpper() & propertyName.Substring(1)

        
'创建属性对象

        '-1表示代码插入到类的最下方
        'vsCMAccess.vsCMAccessPublic表示为public
        Dim codeProperty As CodeProperty = codeClass.AddProperty(propertyName, propertyName, fieldType, -1, vsCMAccess.vsCMAccessPublic)
        
'Getter

        Dim getter As CodeFunction = codeProperty.Getter
        
Dim getterPoint As TextPoint =
 getter.GetStartPoint(vsCMPart.vsCMPartBody)
        
Dim getterEditPoint As EditPoint =
 getterPoint.CreateEditPoint()
        getterEditPoint.Delete(getter.GetEndPoint(vsCMPart.vsCMPartBody))
        getterEditPoint.Insert(vbCrLf)      
'插入回车符

        getterEditPoint.LineUp()
        getterEditPoint.Indent(, 
4)         '缩进4个位置

        getterEditPoint.Insert("return " & fieldName & ";")
        
'Setter

        Dim setter As CodeFunction = codeProperty.Setter
        
Dim setterPoint As TextPoint =
 setter.GetStartPoint(vsCMPart.vsCMPartBody)
        
Dim setterEditPoint As EditPoint =
 setterPoint.CreateEditPoint()
        setterEditPoint.Insert(vbCrLf)     
'插入回车符

        setterEditPoint.LineUp()
        setterEditPoint.Indent(, 
4)         '缩进4个位置

        setterEditPoint.Insert(fieldName & " = value;")
    
End Sub

End Module

 

 

 

 

 

使用Visual Studio 2005 IDE的宏,自动为c#变量生成属性

[ 收藏此页] [ 打印]
作者: IT168 scdsun  
<script>init_Nav();</script>

  我定义了两个Public方法:EncapsulateField和EncapsulateAllFields,分别用于为类的一个变量封装属性,或者为类中所有的变量(非静态)封装属性。

使用上面的宏的方法很简单,选择“工具”>“宏”>“宏资源管理器”就可以看到我们已经创建的宏方法,如下图所示:


假如你已经编写了这样一段代码:
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Demo
{
    
public   class  Person
    {
        
private   int  _id;
        
private   string  _name;
        
private  DateTime _birthDay;
    }
}

将光标移到“_name”变量上,然后双击“EncapsulateField”宏,就运行了该宏。运行后,你可以得到这样的代码:
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Demo
{
    
public   class  Person
    {
        
private   int  _id;
        
private   string  _name;
        
private  DateTime _birthDay;

        
public   string  Name
        {
            
get
            {
                
return  _name;
            }
            
set
            {
                _name 
=  value;
            }
        }
    }
}

可以看到“EncapsulateField”宏已经为private string _name;创建了相应的属性。
EncapsulateAllFields宏只需要将光标放在Person类的代码区域中,就可以正常执行。例如针对上面的代码,EncapsulateAllFields后可以为Person类中的每一个变量都生成相应的属性。(注:上面的代码中Name属性已经有定义,所有试图再添加Name属性时会抛出异常,在EncapsulateAllFields宏定义中,已经将该异常吃掉,所以,可以正确地为所有变量生成属性)。运行后的代码如下:
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Demo
{
    
public   class  Person
    {
        
private   int  _id;
        
private   string  _name;
        
private  DateTime _birthDay;

        
public   string  Name
        {
            
get
            {
                
return  _name;
            }
            
set
            {
                _name 
=  value;
            }
        }

        
public   int  Id
        {
            
get
            {
                
return  _id;
            }
            
set
            {
                _id 
=  value;
            }
        }

        
public  System.DateTime BirthDay
        {
            
get
            {
                
return  _birthDay;
            }
            
set
            {
                _birthDay 
=  value;
            }
        }
    }
}

 

 

 

 

 

在确认上面的宏可以正确运行的情况下,我们还可以为其定义快捷键,进一步提高我们的工作效率。
在Visual Studio 2005 IDE中选择“工具” > “选项”

在“选项”对话框中选择“环境”>“键盘”。
在【显示命令包含】中输入Encap...,可以帮你快速定位到相应的宏命令;
【新快捷键用于】选项中选择“文本编辑器”;
激活【按快捷键】输入框,选择你所希望的快捷键,例如我这里为EncapsulateField定义的快捷键为“Ctrl + `”,为EncapsulateAllFields定义的快捷键为“Ctrl + Shift + `”
点击分配按钮

你就可以在文本编辑器中尽情享用宏给你带来的方便。


补充在Visual Studio 2003中使用的宏:
Visual Studio 2003 IDE与Visual Studio 2005 IDE在处理上稍微有些不一致的地方,需要做如下的调整:

Imports System
Imports EnvDTE
Imports System.Diagnostics

Public  Module EditorHelper
    
' 为一个参数封装一般属性访问器
     Public   Sub  EncapsulateField()
        
Dim  projectItem  As  ProjectItem  =  DTE.ActiveDocument.ProjectItem
        
Dim  fileCodeModel  As  FileCodeModel  =  projectItem.FileCodeModel

        
' 得到当前选定的内容
         Dim  selectText  As  TextSelection  =  DTE.ActiveDocument.Selection
        
' 获取到当前光标的位置
         Dim  point  As  TextPoint  =  selectText.ActivePoint

        Try
            
Dim  codeElement  As  CodeElement  =  fileCodeModel.CodeElementFromPoint(point, vsCMElement.vsCMElementVariable)

            
If  (codeElement  Is   Nothing Then
                Return
            
End   If

            Debug.Assert(codeElement.Kind 
=  vsCMElement.vsCMElementVariable)

            
Dim  codeVar  As  CodeVariable  =  CType(codeElement, CodeVariable)
            
Dim  fieldName  As   String   =  codeVar.Name
            
Dim  codeClass  As  CodeClass  =  CType(codeVar.Parent, CodeClass)

            AddPropertyToClass(codeClass, fieldName, codeVar.Type)
        Catch ex 
As  Exception
            
' 吃掉异常,不做处理或者提示
             MsgBox (ex.Message)
        
End  Try

    
End Sub

    
Public   Sub  EncapsulateAllFields()
        
Dim  projectItem  As  ProjectItem  =  DTE.ActiveDocument.ProjectItem
        
Dim  fileCodeModel  As  FileCodeModel  =  projectItem.FileCodeModel

        Try
            
' 得到当前选定的内容
             Dim  selectText  As  TextSelection  =  DTE.ActiveDocument.Selection
            
' 获取到当前光标的位置
             Dim  point  As  TextPoint  =  selectText.ActivePoint

            
Dim  codeElement  As  CodeElement  =  fileCodeModel.CodeElementFromPoint(point, vsCMElement.vsCMElementClass)
            
Dim  codeClass  As  CodeClass  =  CType(codeElement, CodeClass)

            
Dim  i  As   Integer
            
For  i  =   1   To  codeClass.Members.Count
                
' 如果属性已经定义,会抛出异常
                 ' 在这里处理异常,即使新增的属性已经定义,也可以继续处理下面的代码
                Try
                    
Dim  element  As  CodeElement  =  codeClass.Members.Item(i)
                    
If  (element.Kind  =  vsCMElement.vsCMElementVariable)  Then
                        
Dim  codeVariable  As  CodeVariable  =  CType(element, CodeVariable)
                        
If  ( Not  codeVariable.IsShared)  Then       ' 静态变量不需要增加属性
                            AddPropertyToClass(codeClass, codeVariable.Name, codeVariable.Type)
                        
End   If
                    
End   If
                Catch ex 
As  Exception
                    
' 吃掉异常
                 End  Try
            
Next
        Catch ex 
As  Exception
            
' 可能并没有选择有效的类定义,这时会抛出异常,忽略
             MsgBox (ex.Message)
        
End  Try
    
End Sub

    
' 根据成员的名称的类型,在类对象中插入属性
     Private   Sub  AddPropertyToClass(ByVal codeClass  As  CodeClass, ByVal fieldName  As   String , ByVal fieldType  As   Object )
        
' 生成属性的名称,规则是首先字母大写。如果变量的开头为“_”,移除
         Dim  propertyName  As   String   =  fieldName
        
If  (propertyName.StartsWith( " _ " ))  Then
            propertyName 
=  propertyName.TrimStart( " _ " c)
        
End   If
        propertyName 
=  propertyName.Substring( 0 1 ).ToUpper()  &  propertyName.Substring( 1 )

        
' 创建属性对象
         ' -1表示代码插入到类的最下方
         ' vsCMAccess.vsCMAccessPublic表示为public
         Dim  codeProperty  As  CodeProperty  =  codeClass.AddProperty(propertyName, propertyName, fieldType,  - 1 , vsCMAccess.vsCMAccessPublic)
        
' Getter
         Dim  getter  As  CodeFunction  =  codeProperty.Getter
        
Dim  getterPoint  As  TextPoint  =  getter.GetStartPoint(vsCMPart.vsCMPartBody)
        
Dim  getterEditPoint  As  EditPoint  =  getterPoint.CreateEditPoint()
        getterEditPoint.Delete(getter.GetEndPoint(vsCMPart.vsCMPartBody))
        getterEditPoint.Insert(
" get{ return  "   &  fieldName  &   " ; } " )
        
' Setter
         Dim  setter  As  CodeFunction  =  codeProperty.Setter
        
Dim  setterPoint  As  TextPoint  =  setter.GetStartPoint(vsCMPart.vsCMPartBody)
        
Dim  setterEditPoint  As  EditPoint  =  setterPoint.CreateEditPoint()
        setterEditPoint.Delete(setter.GetEndPoint(vsCMPart.vsCMPartBody))
        setterEditPoint.Insert(
" set{  "   &  fieldName  &   "  = value; } " )
    
End Sub
End  Module



另外,在2003中使用EncapsulateAllFields的宏时,也需要注意一点:在使用时,光标的应该停留在类定义的空白位置,否则使用Dim codeClass As CodeClass = CType(codeElement, CodeClass)方法不能正确获取到类对象(例如,如果光标在构造函数里,获取到的是构造函数对象,这点与2005还是有所区别的)。


参考:
《用Visual Studio 2005创建宏代码生成器》:转载太多,已经不知道原出处


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值