Compartir a través de


Detectar código utilizando el modelo de código (Visual C#)

Los complementos de Visual Studio están desusados en Visual Studio 2013. Debe actualizar los complementos a las extensiones de VSPackage. Para obtener más información sobre la actualización, vea Preguntas más frecuentes: Convertir complementos en extensiones de VSPackage.

El modelo de código de Visual Studio proporciona a los clientes de automatización la posibilidad de detectar definiciones de código en un proyecto y modificar esos elementos de código. El modelo de código actualiza automáticamente todos los objetos a los que se hace referencia cuando se modifican en el editor de código. Por ejemplo, si se hace referencia a un objeto de clase y más adelante un usuario agrega una función nueva, ésta se incluye en la lista entre los miembros. El modelo de código permite que los clientes de automatización no tengan que implementar un analizador para los lenguajes de Visual Studio para poder detectar las definiciones de alto nivel contenidas en un proyecto, como por ejemplo clases, interfaces, estructuras, métodos, propiedades, etc.

El modelo de código central de Visual Studio evita las áreas del código específicas de cada lenguaje, por lo que, por ejemplo, no proporciona un modelo de objetos para las instrucciones de las funciones, ni detalla por completo los parámetros. Para los parámetros, el modelo de código expone solo el tipo y nombre del parámetro y no se proporciona ninguna información en cuanto a si el parámetro es de entrada, salida, opcional, etc. Visual C++ proporciona una versión extendida del modelo de código central destinada a los proyectos de Visual C++. Para obtener información sobre este tema, vea Modelo de código de Visual C++.

Examinar y editar código con el modelo de código

El modelo de código está esencialmente basado en texto, ya que el programa o código del objeto se almacena en archivos de texto. Es posible buscar el código de un proyecto utilizando el modelo de proyecto para pasar por cada uno de los elementos del mismo, y luego comprobar, mediante FileCodeModel, si dicho elemento contiene código. Si un elemento de proyecto contiene elementos de código, dichos elementos pueden devolver objetos desde el editor y el modelo de código puede utilizar el modelo de automatización del editor de texto para modificar código o efectuar análisis local. Si se utiliza el modelo de objetos Editor, se puede solicitar el elemento de código que contiene el punto de inserción del editor o un objeto TextPoint en el nivel de función o de clase.

El punto de entrada principal al modelo de código central de Visual Studio es el objeto CodeModel. En diversos lugares del modelo de código se utiliza una colección CodeElements general. Hay una en el nivel CodeElements y en el nivel de clase o interfaz que devuelve los miembros de estos objetos. Cada uno de los elementos de una colección CodeElements es un objeto CodeElement2, y cada objeto CodeElement2 incorpora una propiedad Kind que identifica de qué tipo es, es decir, clase, interfaz, struct, función, propiedad, variable, etc.

Modelos de código específicos del lenguaje

Visual C++ proporciona una extensión al modelo de código central destinada al código específico de Visual C++. Por ejemplo, si Language indica que cierto elemento de código es un objeto de modelo de código de Visual C++ y Kind = vsCMElementClass, entonces se puede elegir QueryInterface (QI) para CodeClass del modelo de código de Visual Studio o QI para VCCodeClass del modelo de código específico del lenguaje de Visual C++. Para obtener más información sobre el modelo de código específico de Visual C++, vea Cómo: Manipular código mediante el modelo de código de Visual C++ (Visual C#) y Modelo de código de Visual C++.

Notas sobre el modelo de código de Visual Studio

  • Únicamente la implementación del modelo de código de Visual C++ efectúa un modelado específico del lenguaje de las implementaciones de lenguajes de Microsoft.

  • Algunos lenguajes no implementan el modelo de código completo de Visual Studio. Los temas de Ayuda señalan las excepciones cuando existen. La mayor parte de las diferencias entre implementaciones del modelo de código se deben a diferencias funcionales entre los lenguajes. Por ejemplo, no puede agregar funciones a objetos CodeNamespace en Visual Basic ni en Visual C#, porque sólo Visual C++ incorpora definiciones de características de nivel superior.

Descripción

Este complemento recorre los elementos de código de un archivo de Visual Studio. Para ejecutar el ejemplo, debe tener un archivo de código abierto en el editor de código de Visual Studio. Para obtener más información sobre cómo ejecutar los ejemplos, vea Cómo: Compilar y ejecutar los ejemplos de código del modelo de objetos de automatización.

Código

// Add-in code.
using System.Windows.Forms;
public void OnConnection(object application,
 Extensibility.ext_ConnectMode connectMode, object addInInst, ref
 System.Array custom)
{
    _applicationObject = (_DTE2)application;
    _addInInstance = (AddIn)addInInst;
    // Pass the applicationObject member variable to the code example.
    OutlineCode((DTE2)_applicationObject); 
}

public void OutlineCode( DTE2 dte ) 
{ 
    FileCodeModel fileCM = 
      dte.ActiveDocument.ProjectItem.FileCodeModel; 
    CodeElements elts = null; 
    elts = fileCM.CodeElements; 
    CodeElement elt = null; 
    int i = 0; 
    MessageBox.Show( "about to walk top-level code elements ..."); 
    for ( i=1; i<=fileCM.CodeElements.Count; i++ ) 
    { 
        elt = elts.Item( i ); 
        CollapseElt( elt, elts, i ); 
    } 
} 

public void CollapseElt( CodeElement elt, CodeElements elts, long loc ) 
{ 
    EditPoint epStart = null; 
    EditPoint epEnd = null; 
    epStart = elt.StartPoint.CreateEditPoint(); 
    // Do this because we move it later.
    epEnd = elt.EndPoint.CreateEditPoint(); 
    epStart.EndOfLine(); 
    if ( ( ( elt.IsCodeType ) & ( elt.Kind !=
      vsCMElement.vsCMElementDelegate ) ) ) 
    { 
        MessageBox.Show( "got type but not a delegate, 
          named : " + elt.Name); 
        CodeType ct = null; 
        ct = ( ( EnvDTE.CodeType )( elt ) ); 
        CodeElements mems = null; 
        mems = ct.Members; 
        int i = 0; 
        for ( i=1; i<=ct.Members.Count; i++ ) 
        { 
            CollapseElt( mems.Item( i ), mems, i ); 
        } 
    } 
    else if ( ( elt.Kind == vsCMElement.vsCMElementNamespace ) ) 
    { 
        MessageBox.Show( "got a namespace, named: " + elt.Name); 
        CodeNamespace cns = null; 
        cns = ( ( EnvDTE.CodeNamespace )( elt ) ); 
        MessageBox.Show( "set cns = elt, named: " + cns.Name); 

        CodeElements mems_vb = null; 
        mems_vb = cns.Members; 
        MessageBox.Show( "got cns.members"); 
        int i = 0; 

        for ( i=1; i<=cns.Members.Count; i++ ) 
        { 
            CollapseElt( mems_vb.Item( i ), mems_vb, i ); 
        } 
    } 
}

Los valores de los elementos del modelo de código pueden cambiar

Los valores asignados a los elementos del modelo de código, como las clases, structs, funciones, atributos y delegados, entre otros, pueden cambiar después de realizar algunas modificaciones. Por lo tanto, no se puede suponer que los valores permanezcan estáticos.

Si asigna un elemento de modelo de código a una variable local, por ejemplo, y establece un valor de propiedad para esta variable local, ésta no contendrá un elemento de modelo de código válido cuando haga referencia a ella más adelante. De hecho, podría contener un elemento del modelo de código diferente.

Tenga en cuenta una función denominada "MyFunction" asignada a la variable CodeFunction y, a continuación, se establece la propiedad Name de CodeFunction en el valor "YourFunction". Después de asignar esta variable, no es seguro que la variable local represente la misma CodeFunction. En consecuencia, obtener acceso al valor de propiedad podría dar como resultado E_FAIL.

La práctica recomendada para solucionar esta solución es reasignar de forma explícita la variable local al elemento del modelo de código correcto antes de obtener acceso a sus valores de propiedad. A continuación se muestra un ejemplo de cómo realizarlo. (El código se encuentra en forma de complemento.)

Descripción

Este complemento demuestra el modo correcto de obtener acceso a los valores de CodeElements para recuperar el valor apropiado. Para obtener más información acerca de cómo ejecutar los ejemplos, vea Cómo: Compilar y ejecutar los ejemplos de código del modelo de objetos de automatización.

Código

[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);
    }
}

Nota

Establecer las propiedades de los elementos secundarios del elemento del modelo de código no refleja este comportamiento.Solo las propiedades que afectan directamente a CodeElement, como el nombre del elemento, el tipo de función, la signatura de un método, etc., muestran este comportamiento no determinista.

Además, este ejemplo sólo funciona si el nuevo nombre de CodeElement es único entre sus nodos relacionados.Esto es porque la propiedad Item devuelve la primera coincidencia que no funciona para las propiedades y métodos sobrecargados, las clases parciales o los espacios de nombres con el mismo nombre.

Vea también

Tareas

Cómo: Compilar el código de ejemplo de extensibilidad del modelo de código de Visual C++

Cómo: Crear un complemento

Tutorial: Crear un asistente

Cómo: Manipular código mediante el modelo de código de Visual C++ (Visual C#)

Cómo: Manipular código mediante el modelo de código de Visual C++ (Visual Basic)

Conceptos

Detectar código utilizando el modelo de código (Visual Basic)

Modelo de código de Visual C++

Gráfico del modelo de objetos de automatización

Otros recursos

Crear y controlar las ventanas del entorno

Crear complementos y asistentes

Referencia de automatización y extensibilidad