Découverte de code à l'aide du modèle de code (Visual C#)

Les compléments Visual Studio sont déconseillés dans Visual Studio 2013. Vous devriez mettre vos compléments à niveau vers des extensions VSPackage. Pour plus d'informations sur les mises à jour, consultez FAQ : conversion de compléments en extensions VSPackage.

Le modèle de code de Visual Studio donne aux clients Automation la possibilité de découvrir des définitions de code dans un projet et de modifier ces éléments de code. Le modèle de code met automatiquement à jour tous les objets référencés lorsque des modifications sont apportées dans l'éditeur de code. Par exemple, si vous faites référence à un objet de classe et qu'un utilisateur ajoute par la suite une nouvelle fonction, celle-ci est répertoriée au sein des membres. Grâce au modèle de code, les clients Automation n'ont pas à implémenter d'analyseur pour les langages Visual Studio afin de découvrir les définitions de niveau supérieur d'un projet, telles que les classes, les interfaces, les structures, les méthodes, les propriétés, etc.

Le modèle de code principal de Visual Studio évite les zones de code propres au langage. Il ne fournit donc pas, par exemple, de modèle objet pour les instructions des fonctions ou de détails complets sur les paramètres. Pour les paramètres, le modèle de code expose uniquement le type et le nom du paramètre, et aucune information n'est fournie pour indiquer si le paramètre est d'entrée, de sortie, facultatif, etc. Visual C++ offre une version étendue du modèle de code principal ciblé vers des projets Visual C++. Pour plus d'informations à ce sujet, consultez Modèle de code Visual C++.

Examen et modification de code avec le modèle de code

Le modèle de code est principalement basé sur le texte dans la mesure où le programme ou le code du projet est stocké dans des fichiers texte. Vous pouvez localiser le code d'un projet en utilisant le modèle de projet pour visiter chaque élément de projet, puis vérifier si l'élément de projet contient un code à l'aide de FileCodeModel. Si un élément de projet contient des éléments de code, ces éléments peuvent retourner des objets depuis l'éditeur, et le modèle de code peut utiliser le modèle Automation de l'éditeur de texte pour modifier le code ou effectuer une analyse localisée. À l'aide du modèle objet de l'éditeur, vous pouvez interroger l'élément de code contenant le point d'insertion de l'éditeur ou un objet TextPoint présent au niveau de la fonction ou de la classe.

Le point d'entrée principal du modèle de code de Visual Studio est l'objet CodeModel. Une collection CodeElements générale est utilisée à plusieurs endroits dans le modèle de code. Il y en a une au niveau de CodeElements et au niveau de la classe ou de l'interface retournant les membres de ces objets. Chaque élément d'une collection CodeElements est un objet CodeElement2, et chaque objet CodeElement2 dispose d'une propriété Kind qui identifie son type, à savoir s'il s'agit d'une classe, d'une interface, d'une structure, d'une fonction, d'une propriété, d'une variable, etc.

Modèles de code propres au langage

Visual C++ fournit une extension au modèle de code principal pour cibler le code spécifique à Visual C++. Par exemple, si Language indique qu'un élément de code particulier est un objet du modèle de code Visual C++ et Kind = vsCMElementClass, vous pouvez choisir d'appeler QueryInterface (QI) pour CodeClass à partir du modèle de code Visual Studio ou QI pour VCCodeClass à partir du modèle de code spécifique au langage Visual C++. Pour plus d'informations sur le modèle de code spécifique à Visual C++, consultez Comment : manipuler le code à l'aide du modèle de code Visual C++ (Visual C#) et Modèle de code Visual C++.

Remarques relatives au modèle de code de Visual Studio

  • Seule l'implémentation du modèle de code de Visual C++ effectue une modélisation propre au langage des implémentations de langage Microsoft.

  • Certains langages n'implémentent pas l'intégralité du modèle de code de Visual Studio. Des rubriques d'aide signalent les éventuelles exceptions. La plupart des différences entre les diverses implémentations du modèle de code sont dues à des différences fonctionnelles entre les langages. Par exemple, vous ne pouvez pas ajouter de fonctions aux objets CodeNamespace de Visual Basic ou Visual C# car seul Visual C++ dispose de définitions de fonctions de niveau supérieur.

Description

Ce complément traverse les éléments de code d'un fichier Visual Studio. Pour exécuter l'exemple, vous devez disposer d'un fichier de code ouvert dans l'éditeur de code Visual Studio. Pour plus d'informations sur l'exécution des exemples, consultez Comment : compiler et exécuter les exemples de code du modèle objet Automation.

Code

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

Les valeurs d'élément de modèle de code peuvent être modifiées

Les valeurs assignées d'éléments de modèle de code, tels que des classes, des structures, des fonctions, des attributs, des délégués, etc., peuvent changer après certains types de modifications. Par conséquent, vous ne pouvez pas supposer que ces valeurs resteront statiques.

Si vous assignez un élément de modèle de code à une variable locale, par exemple, et que vous définissez ensuite une valeur de propriété pour cette variable locale, la variable locale peut ne pas contenir un élément de modèle de code valide lorsque vous la référencez ultérieurement. En fait, elle peut même contenir un élément de modèle de code différent.

Prenons l'exemple d'une classe contenant une fonction appelée "MyFunction", qui est assignée à une variable CodeFunction. La valeur "YourFunction" est ensuite affectée à la propriété Name de CodeFunction. Après l'assignation de cette variable, vous n'avez plus la garantie que votre variable locale représente le même CodeFunction. Par la suite, l'accès à la propriété peut, en conséquence, retourner E_FAIL.

Pour gérer cette situation, il est recommandé de réassigner explicitement votre variable locale afin de corriger l'élément de modèle de code avant d'accéder à ses valeurs de propriété. Le code ci-après indique comment effectuer cette opération. (Il se présente sous la forme d'un complément.)

Description

Ce complément illustre la façon correcte d'accéder aux valeurs de CodeElements afin que la valeur appropriée soit récupérée. Pour plus d'informations sur l'exécution des exemples, consultez Comment : compiler et exécuter les exemples de code du modèle objet Automation.

Code

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

Notes

La définition des propriétés des éléments enfants de votre élément de modèle de code ne présente pas ce comportement.Seules les propriétés qui affectent directement CodeElement— telles que le nom de l'élément, le type d'une fonction, la signature d'une méthode, etc. — montrent ce comportement non déterministe.

De plus, cet exemple ne fonctionne que si le nouveau nom de CodeElement est unique parmi ses frères.En effet, la propriété Item retourne la première correspondance, ce qui ne fonctionne pas pour les méthodes/propriétés surchargées, les classes partielles ou les espaces de noms portant le même nom.

Voir aussi

Tâches

Comment : compiler l'exemple de code pour l'extensibilité du modèle de code Visual C++

Comment : créer un complément

Procédure pas à pas : création d'un Assistant

Comment : manipuler le code à l'aide du modèle de code Visual C++ (Visual C#)

Comment : manipuler le code à l'aide du modèle de code Visual C++ (Visual Basic)

Concepts

Découverte de code à l'aide du modèle de code (Visual Basic)

Modèle de code Visual C++

Graphique Modèle d'objet Automation

Autres ressources

Création et contrôle de fenêtres d'environnement

Création de compléments et d'Assistants

Guide de référence de l'extensibilité et de l'automation