Поделиться через


Практическое руководство. Поиск кода при помощи модели кода (Visual Basic)

Обновлен: Ноябрь 2007

Модель кода Visual Studio позволяет клиентам автоматизации находить определения кода в проекте и изменять эти элементы кода. При выполнении изменений в редакторе кода модель кода автоматически обновляет все объекты, на которые имеется ссылка. Например, если имеется ссылка для объекта класса и в дальнейшем пользователь добавит новую функцию, она появится в списке в числе членов. Модель кода позволяет клиентам автоматизации находить определения верхнего уровня в проекте (например, классы, интерфейсы, структуры, методы, свойства и т. д.) без реализации анализатора для языков Visual Studio.

Базовая модель кода Visual Studio не затрагивает участки кода, специфичные для языка, поэтому, например, она не реализует ни объектную модель для операторов внутри функций, ни детальное описание параметров. Для параметров модель кода показывает только тип и имя параметра, но не предоставляет никаких сведений о том, является ли параметр входным, выходным, необязательным и т. д. Visual C++ предлагает расширенную версию базовой модели кода, предназначенную для проектов Visual C++. Дополнительные сведения об этом см. в разделе Модель кода Visual C++.

Проверка и редактирование кода с помощью модели кода

Модель кода в основном является текстовой, так как программа или код в проекте хранится в текстовых файлах. При помощи модели кода можно выполнить поиск кода проекта и перейти к каждому элементу проекта, а затем проверить, содержит ли данный элемент проекта код, используя FileCodeModel. Если элемент проекта содержит элементы кода, они могут возвращать объекты редактора, а модель кода может использовать модель автоматизации текстового редактора для изменения кода или выполнения локального разбора. Используя объектную модель редактора, можно запросить элемент кода, содержащий положение курсора редактора, или объект TextPoint на уровне функции или класса.

Основной точкой входа для базовой модели кода Visual Studio является объект CodeModel. В нескольких местах модели кода используется общая коллекция CodeElements. Эта коллекция находится на уровне CodeElements и на уровне класса или интерфейса, возвращающего члены этих объектов. Каждый элемент коллекции CodeElements представляет собой объект CodeElement2, и у каждого объекта CodeElement2 имеется свойство Kind, определяющее его тип: является ли он классом, интерфейсом, структурой, функцией, свойством, переменной и т. д.

Объекты модели кода, зависящие от языка

Visual C++ предоставляет расширение базовой модели кода для целевого кода, зависящего от Visual C++. Например, если Languageуказывает, что данный элемент кода является объектом модели кода Visual C++ и Kind = vsCMElementClass, можно выбрать либо QueryInterface (QI) для CodeClass из модели кода Visual Studio, либо QI для VCCodeClass из модели кода, зависящей от языка Visual C++. Дополнительные сведения о модели кода, зависящей от языка Visual C++ см. в разделах Практическое руководство. Управление кодом при помощи модели кода Visual C++ (Visual Basic) и Модель кода Visual C++.

Замечания о базовой модели кода Visual Studio

  • Только реализация модели кода Visual C++ выполняет зависящее от языка моделирование для реализации языка Microsoft.

  • В некоторых реализациях языка не реализуется полная модель кода Visual Studio. Исключения, если они есть, указаны в справке. Большинство различий между реализациями модели кода вызвано функциональными различиями языков. Например, нельзя добавить функции к объектам CodeNamespace в Visual Basic или Visual C#, поскольку определять функции на верхнем уровне позволяет только Visual C++.

Описание

Эта надстройка переходит по различным элементам кода в файле Visual Studio. Для выполнения примера файл исходного кода необходимо открыть в редакторе кода Visual Studio. Дополнительные сведения о запуске этих примеров см. в разделе Практическое руководство. Компиляция и выполнение примеров кода модели объектов автоматизации.

Код

' Add-in code.
Public Sub OnConnection(ByVal application As Object, ByVal _
 connectMode As ext_ConnectMode, ByVal addInInst As Object,  _
 ByRef custom As Array) Implements IDTExtensibility2.OnConnection
    _applicationObject = CType(application, DTE2)
    _addInInstance = CType(addInInst, AddIn)
    ' Pass the applicationObject member variable to the code example.
    OutlineCode(_applicationObject)
End Sub

Sub OutlineCode(ByVal dte As DTE2)
    Dim fileCM As FileCodeModel2 _
      = CType(dte.ActiveDocument.ProjectItem.FileCodeModel, _
      FileCodeModel2)
    Dim elts As CodeElements
    elts = fileCM.CodeElements
    Dim elt As CodeElement2
    Dim i As Integer
    MsgBox("About to walk top-level elements ...")
    For i = 1 To fileCM.CodeElements.Count
        elt = CType(elts.Item(i), CodeElement2)
        CollapseElt(elt, elts, i)
    Next
End Sub

Sub CollapseElt(ByVal elt As CodeElement2, ByVal elts As _
    CodeElements, ByVal loc As Long)
    Dim epStart As EditPoint2
    Dim epEnd As EditPoint2
    epStart = CType(elt.StartPoint.CreateEditPoint, EditPoint2)
    ' Do this since we move it later.
    epEnd = CType(elt.EndPoint.CreateEditPoint, EditPoint2)
    epStart.EndOfLine()
    If ((elt.IsCodeType) And (elt.Kind <> _
      vsCMElement.vsCMElementDelegate)) Then
        MsgBox("Got type but not a delegate, named : " & elt.Name)
        Dim ct As CodeType
        ct = CType(elt, CodeType)
        Dim mems As CodeElements
        mems = ct.Members
        MsgBox("Set mems = ct.members")
        Dim i As Integer
        For i = 1 To ct.Members.Count
            CollapseElt(CType(mems.Item(i), CodeElement2), mems, i)
        Next
    ElseIf (elt.Kind = vsCMElement.vsCMElementNamespace) Then
        MsgBox("Got a namespace, named: " & elt.Name)
        Dim cns As CodeNamespace
        cns = CType(elt, CodeNamespace)
        MsgBox("set cns = elt, named: " & cns.Name)

        Dim mems_vb As CodeElements
        mems_vb = cns.Members
        MsgBox("Got cns.members")
        Dim i As Integer

        For i = 1 To cns.Members.Count
            CollapseElt(CType(mems_vb.Item(i), CodeElement2),  _
              mems_vb, i)
        Next
    End If
End Sub

Изменение значений элементов модели кода

Назначенные значения элементов модели кода, таких как классы, структуры, функции, атрибуты, делегаты и т. п., после внесения определенных типов правок могут изменяться. Следовательно, нельзя предполагать, что значения останутся статическими.

Например, если локальной переменной назначить элемент модели кода, а затем задать значение свойства для этой локальной переменной, то в случае создания ссылки на эту переменную позднее в ней может быть недопустимый элемент модели кода. Фактически в ней даже может быть другой элемент модели кода.

Предположим, что имеется класс с функцией с именем "MyFunction", которое назначено переменной CodeFunction, а затем свойству NameCodeFunction задается значение "YourFunction". После такого присвоения переменной уже нельзя гарантировать, что локальная переменная представляет ту же CodeFunction. Следовательно, обращение к значению свойства может в результате привести к E_FAIL.

В этом случае рекомендуется выполнить явное переназначение правильного элемента модели кода локальной переменной, прежде чем будет выполнено обращение к значениям ее свойств. Пример того, как это можно сделать, показан ниже. (Код представлен в виде надстройки.)

Описание

Эта надстройка демонстрирует правильный способ обращения к значениям CodeElements, чтобы можно было извлечь правильное значение. Дополнительные сведения о запуске этих примеров см. в разделе Практическое руководство. Компиляция и выполнение примеров кода модели объектов автоматизации.

Код

[Visual Basic]

Public Sub OnConnection(ByVal application As Object, ByVal _
  connectMode As ext_ConnectMode, ByVal addInInst As Object, _
  ByRef custom As Array) Implements IDTExtensibility2.OnConnection
    _applicationObject = CType(application, DTE2)
    _addInInstance = CType(addInInst, AddIn)
    ReassignValue(_applicationObject)
End Sub

Sub ReassignValue(ByVal dte As DTE2)
    ' Before running, create a new Windows application project,
    ' and then add a function to it named MyFunction.
    Try
        Dim myFCM As FileCodeModel = _
          dte.ActiveDocument.ProjectItem.FileCodeModel
        ' Change the MyFunction name in Form1 class to
        ' the name, OtherFunction.
        Dim myClass1 As CodeClass = _
          CType(myFCM.CodeElements.Item("Form1"), CodeClass2)
        Dim myFunction As CodeFunction = _
          CType(myClass1.Members.Item("MyFunction"), CodeFunction2)
        myFunction.Name = "OtherFunction"
        myFunction = CType(myClass1.Members.Item("OtherFunction"), _
          CodeFunction2)
    Catch ex As Exception
        MsgBox(ex.ToString)
    End Try
End Sub

[C#]

public void OnConnection(object application, ext_ConnectMode 
  connectMode, object addInInst, ref Array custom)
{
    _applicationObject = (DTE2)application;
    _addInInstance = (AddIn)addInInst;
    ReassignValue(_applicationObject);
}

// Before running, create a new Windows application project,
// and then add a function to it named MyFunction.
public void ReassignValue(DTE2 dte)
{
    try
    {
        FileCodeModel myFCM = 
          dte.ActiveDocument.ProjectItem.FileCodeModel;
        // Change the MyFunction name in Form1 class to
        // the name, OtherFunction.
        CodeClass myClass1 = 
          (CodeClass2)myFCM.CodeElements.Item("Form1");
        CodeFunction myFunction = 
          (CodeFunction2)myClass1.Members.Item("MyFunction");
        myFunction.Name = "OtherFunction";
        myFunction = 
          (CodeFunction2)myClass1.Members.Item("OtherFunction");
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}
tz746te4.alert_note(ru-ru,VS.90).gifПримечание.

Настройка свойств дочерних элементов для элемента модели кода не демонстрирует это поведение. Только свойства, которые напрямую влияют на CodeElement, такие как имя элемента, тип функции, подпись метода и т.д., демонстрируют такое недетерминированное поведение.

Кроме того, данный пример работает только в том случае, если новое имя CodeElement является уникальным среди своих одноуровневых элементов. Причина этого заключается в том, что свойство Item возвращает первое совпадение, которое не работает с перегруженными методами/свойствами, разделяемыми классами или пространствами имен с тем же именем.

См. также

Задачи

Практическое руководство. Компиляция примера кода для расширения модели кода Visual C++

Практическое руководство. Создание надстройки

Пошаговое руководство. Создание мастера

Практическое руководство. Управление кодом при помощи модели кода Visual C++ (Visual C#)

Основные понятия

Практическое руководство. Поиск кода при помощи модели кода (Visual C#)

Модель кода Visual C++

Диаграмма модели объектов автоматизации

Модель кода Visual C++

Другие ресурсы

Создание окон среды и управление ими

Создание надстроек и мастеров

Справочник по автоматизации и возможностям расширения среды