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++
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)
Graphique Modèle d'objet Automation
Autres ressources
Création et contrôle de fenêtres d'environnement