Ermitteln von Code über das Codemodell (Visual C#)
Add-Ins für Visual Studio sind in Visual Studio 2013 veraltet. Sie müssen für Ihre Add-Ins ein Upgrade auf VSPackage-Erweiterungen durchführen. Weitere Informationen über das Durchführen eines Upgrades finden Sie unter FAQ: Konvertieren von Add-Ins in VSPackage-Erweiterungen.
Durch das Codemodell von Visual Studio können Automatisierungsclients Codedefinitionen in einem Projekt ermitteln und diese Codeelemente ändern. Bei jeder Änderungen im Code-Editor aktualisiert das Codemodell automatisch alle Objekte, auf die zuvor verwiesen wurde. Wenn Sie beispielsweise auf ein Klassenobjekt verweisen und ein Benutzer zu einem späteren Zeitpunkt eine neue Funktion hinzufügt, wird diese bei den Membern aufgelistet. Durch das Codemodell erübrigt es sich für Automatisierungsclients, einen Parser für Visual Studio-Sprachen zu implementieren, um in einem Projekt Definitionen auf höheren Ebenen wie Klassen, Schnittstellen, Strukturen, Methoden, Eigenschaften usw. ermitteln zu können.
Das Hauptcodemodell von Visual Studio vermeidet sprachspezifische Codebereiche und stellt daher z. B. auch kein Objektmodell für Funktionsanweisungen oder vollständige Angaben zu Parametern bereit. Parameterangaben umfassen lediglich den jeweiligen Typ und Namen. Weitere Informationen, ob es sich z. B. um Eingabe-, Ausgabe- oder optionale Parameter handelt, sind nicht verfügbar. Visual C++ stellt eine erweiterte Version des Hauptcodemodells bereit, das für Visual C++-Projekte verwendet wird. Weitere Informationen hierzu finden Sie unter Visual C++-Codemodell.
Überprüfen und Bearbeiten von Code mit dem Codemodell
Das Codemodell ist primär textbasiert, d. h. das Programm oder der Code im Projekt werden in Textdateien gespeichert. Die Suche nach einem Projektcode erfolgt mithilfe des Projektmodells, mit dem Sie zu jedem Projektelement gelangen. Durch Anwendung von FileCodeModel können Sie überprüfen, ob ein Projektelement Code enthält. Sind Codeelemente in einem Projektelement enthalten, können diese Objekte vom Editor zurückgeben. Das Automatisierungsmodell des Text-Editors wird vom Codemodell verwendet, um Code zu ändern oder lokalisierte Analysen durchzuführen. Mithilfe des Editor-Objektmodells können Sie das Codeelement anfordern, das die Einfügemarke des Editors enthält, oder Sie können ein TextPoint-Objekt auf Funktions- oder Klassenebene anfordern.
Der primäre Einstiegspunkt in das Hauptcodemodell von Visual Studio ist das CodeModel-Objekt. Im Codemodell wird an mehreren Stellen eine allgemeine CodeElements-Auflistung verwendet. Eine Auflistung befindet sich auf der CodeElements-Ebene, eine weitere auf der Klassen- oder Schnittstellenebene, die die Member dieser Objekte zurückgibt. Jedes Element einer CodeElements-Auflistung ist ein CodeElement2-Objekt. Jedes CodeElement2-Objekt verfügt über eine Kind-Eigenschaft zur Identifizierung des Typs, z. B. Klasse, Schnittstelle, Struktur, Funktion, Eigenschaft, Variable usw.
Sprachspezifische Codemodelle
Visual C++ stellt eine Erweiterung für das Hauptcodemodell zur Verwendung von Visual C++-spezifischem Code bereit. Wird beispielsweise durch Language angezeigt, dass das jeweilige Codeelement ein Objekt für das Visual C++-Codemodell ist und Kind = vsCMElementClass gegeben ist, können Sie entweder QueryInterface (QI) für CodeClass aus dem Visual Studio-Codemodell oder QI für VCCodeClass aus dem sprachspezifischen Visual C++-Codemodell auswählen. Weitere Informationen zum spezifischen Codemodell von Visual C++ finden Sie unter Gewusst wie: Bearbeiten von Code mit dem Visual C++-Codemodell (Visual C#) und Visual C++-Codemodell
Hinweise zum Codemodell von Visual Studio
Eine sprachspezifische Gestaltung der Sprachimplementierungen von Microsoft ist nur mit der Implementierung des Codemodells von Visual C++ möglich.
Einige Sprachen implementieren nicht das vollständige Visual Studio-Codemodell. Hilfethemen weisen ggf. auf Ausnahmen hin. Die meisten Unterschiede zwischen den Codemodellimplementierungen sind auf funktionale Besonderheiten der einzelnen Sprachen zurückzuführen. So ist es beispielsweise nicht möglich, CodeNamespace-Objekten in Visual Basic oder Visual C# Funktionen hinzuzufügen, da nur Visual C++ über Funktionsdefinitionen höchster Ebene verfügt.
Beschreibung
Dieses Add-In stellt exemplarisch die Codeelemente einer Visual Studio-Datei vor. Um dieses Beispiel ausführen zu können, muss im Visual Studio-Code-Editor eine Codedatei geöffnet sein. Informationen zum Ausführen der Beispiele finden Sie unter Gewusst wie: Kompilieren und Ausführen der Codebeispiele für das Automatisierungsobjektmodell.
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 );
}
}
}
Änderungsverhalten von Codemodellelementwerten
Die zugeordneten Werte von Codemodellelementen (z. B. Klassen, Strukturen, Funktionen, Attribute, Delegaten usw.) können sich nach bestimmen Bearbeitungsvorgängen ändern. Sie können daher nicht davon ausgehen, dass die Werte statisch bleiben.
Wenn Sie beispielsweise einer lokalen Variablen ein Codemodellelement zuordnen und dann einen Eigenschaftswert für diese lokale Variable festlegen, enthält die lokale Variable möglicherweise kein gültiges Codemodellelement, wenn Sie später auf sie verweisen. Tatsächlich kann sie sogar ein anderes Codemodellelement enthalten.
Sie sollten eine Klasse mit der Funktion "MyFunction" verwenden, die einer CodeFunction-Variablen zugeordnet ist. Dann wird die Name-Eigenschaft der CodeFunction auf den Wert "YourFunction" festgelegt. Nach dieser Variablenzuordnung ist nicht mehr sichergestellt, dass die lokale Variable dieselbe CodeFunction darstellt. Anschließend wird beim Zugreifen auf den Wert der Eigenschaft möglicherweise E_FAIL als Ergebnis zurückgegeben.
Als Vorgehensweise in dieser Situation wird empfohlen, die lokale Variable explizit dem richtigen Codemodellelement zuzuordnen, bevor auf die Eigenschaftswerte zugegriffen wird. Im Folgenden ein Beispiel für diese Vorgehensweise. (Der Code liegt als Add-In vor.)
Beschreibung
In diesem Add-In wird die richtige Vorgehensweise beim Zugreifen auf Werte für CodeElements veranschaulicht, sodass der richtige Wert abgerufen wird. Informationen zum Ausführen der Beispiele finden Sie unter Gewusst wie: Kompilieren und Ausführen der Codebeispiele für das Automatisierungsobjektmodell.
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);
}
}
Hinweis
Wenn Sie die Eigenschaften von untergeordneten Elementen des Codemodellelements festlegen, tritt dieses Verhalten nicht auf.Nur Eigenschaften, die CodeElement direkt betreffen (z. B. der Name des Elements, der Typ einer Funktion, die Signatur einer Methode usw.), weisen dieses nicht deterministische Verhalten auf.
Dieses Beispiel funktioniert zudem nur, wenn der neue Name des CodeElement unter den gleichgestellten Elementen eindeutig ist.Der Grund dafür ist, dass die Item-Eigenschaft die erste Übereinstimmung zurückgibt. Dies funktioniert nicht für überladene Methoden bzw. Eigenschaften, partielle Klassen oder Namespaces mit demselben Namen.
Siehe auch
Aufgaben
Gewusst wie: Kompilieren von Beispielcode für die Erweiterbarkeit des Visual C++-Codemodells
Gewusst wie: Erstellen von Add-Ins
Exemplarische Vorgehensweise: Erstellen eines Assistenten
Gewusst wie: Bearbeiten von Code mit dem Visual C++-Codemodell (Visual C#)
Gewusst wie: Bearbeiten von Code mit dem Visual C++-Codemodell (Visual Basic)
Konzepte
Ermitteln von Code über das Codemodell (Visual Basic)
Diagramm "Automationsobjektmodell"
Weitere Ressourcen
Erstellen und Steuern von Umgebungsfenstern