Condividi tramite


Individuazione di codice mediante il modello di codice (Visual C#)

Il modello di codice di Visual Studio consente ai client di automazione di rilevare definizioni di codice all'interno di un progetto e di modificarne gli elementi. Il modello di codice aggiorna automaticamente tutti gli oggetti a cui viene fatto riferimento ogni volta che vengono apportate modifiche all'interno dell'editor del codice. Se, ad esempio, si fa riferimento a un oggetto classe e successivamente un utente aggiunge una nuova funzione, essa verrà elencata tra i membri. Grazie al modello di codice, non è necessario che i client di automazione implementino un parser per i linguaggi Visual Studio per rilevare definizioni ad alto livello di un progetto, ad esempio classi, interfacce, strutture, metodi, proprietà e così via.

Il modello di codice di base di Visual Studio ignora le aree di codice specifiche del linguaggio, ad esempio non fornisce un modello a oggetti per le istruzioni nelle funzioni né offre informazioni dettagliate sui parametri. Per quanto riguarda i parametri, il modello di codice espone esclusivamente il tipo e il nome del parametro, senza specificare se si tratta di un parametro di input, di output, facoltativo e così via. In Visual C++ è disponibile una versione estesa del modello di codice di base destinata ai progetti Visual C++. Per ulteriori informazioni, vedere Modello di codice Visual C++.

Analisi e modifica del codice mediante il Modello codice

Il modello di codice è principalmente basato su testo, poiché il programma o il codice contenuto nei progetti è archiviato in file di testo. È possibile trovare il codice di un progetto utilizzando il modello del progetto per visitare ogni elemento di progetto, quindi utilizzare la proprietà FileCodeModel per verificare che ogni elemento contenga codice. Se un elemento di progetto contiene elementi di codice, questi possono restituire oggetti dall'editor e il modello di codice può utilizzare il modello di automazione dell'editor di testo per modificare il codice o eseguire l'analisi localizzata. Tramite il modello a oggetti dell'editor è possibile richiedere l'elemento di codice contenente il punto di inserimento dell'editor o un oggetto TextPoint a livello di funzione o di classe.

Il punto di ingresso principale del modello di codice di base di Visual Studio è l'oggetto CodeModel. Un insieme CodeElements generale viene utilizzato in varie parti del modello di codice. Uno si trova a livello della proprietà CodeElements e a livello della classe o dell'interfaccia che restituisce i membri di questi oggetti. Ogni elemento di un insieme CodeElements è un oggetto CodeElement2 e ogni oggetto CodeElement2 dispone di una proprietà Kind che ne identifica il tipo, che si tratti di classe, interfaccia, struttura, funzione, proprietà, variabile e così via.

Modelli di codice specifici del linguaggio

In Visual C++ è disponibile un'estensione al modello di codice di base destinata al codice specifico di Visual C++. Se, ad esempio, la proprietà Language  indica che un determinato elemento di codice è un oggetto del modello di codice di Visual C++ e Kind = vsCMElementClass, è possibile scegliere di eseguire QI (QueryInterface) per CodeClass dal modello di codice di Visual Studio o QI per VCCodeClass dal modello di codice specifico del linguaggio Visual C++. Per ulteriori informazioni sul modello di codice specifico di Visual C++, vedere Procedura: modificare il codice tramite il modello di codice di Visual C++ (Visual C#) e Modello di codice Visual C++.

Note relative al modello di codice di Visual Studio

  • Solo l'implementazione del modello di codice di Visual C++ esegue la modellazione specifica del linguaggio per le implementazioni dei linguaggi Microsoft.

  • In alcuni linguaggi non è implementato l’intero modello di codice di Visual Studio. Negli argomenti della Guida sono segnalate le eventuali eccezioni. La maggior parte delle differenze tra implementazioni del modello di codice è dovuta a differenze funzionali tra i linguaggi. Non è ad esempio possibile aggiungere funzioni a oggetti CodeNamespace in Visual Basic o Visual C# poiché solo in Visual C++ sono disponibili definizioni di funzioni di primo livello.

Descrizione

In questo componente aggiuntivo vengono esaminati gli elementi di codice di un file Visual Studio. Per eseguire l'esempio, è necessario che un file di codice sia aperto nell'editor del codice di Visual Studio. Per ulteriori informazioni su come eseguire gli esempi, vedere Procedura: compilare ed eseguire gli esempi di codice del modello a oggetti di automazione.

Codice

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

Possibile modifica dei valori degli elementi del modello di codice

I valori assegnati degli elementi del modello di codice, quali classi, strutture, funzioni, attributi, delegati e così via, possono cambiare dopo alcuni tipi di modifiche. Di conseguenza, non è possibile presupporre che i valori rimarranno statici.

Se, ad esempio, si assegna un elemento del modello di codice a una variabile locale e si imposta un valore di proprietà per tale variabile, quest'ultima non potrà contenere un elemento del modello di codice quando si farà successivamente riferimento ad essa. In effetti, potrà inoltre contenere un elemento differente del modello di codice.

Si consideri una classe contenente una funzione denominata "MyFunction" assegnata a una variabile CodeFunction e che la proprietà Name della variabile CodeFunction sia impostata sul valore "YourFunction". Dopo l'assegnazione di questa variabile, non si avrà più la garanzia che la variabile locale rappresenti la stessa variabile CodeFunction. Se si accede, in un secondo momento, al valore della proprietà, potrebbe essere restituito lo stato E_FAIL.

In tali situazioni si consiglia di riassegnare in modo esplicito la variabile locale all'elemento del modello di codice corretto prima di accedere ai relativi valori di proprietà. Di seguito viene illustrato un esempio della procedura da eseguire: il codice viene presentato nella forma di un componente aggiuntivo.

Descrizione

Questo componente aggiuntivo dimostra il modo corretto per accedere ai valori di CodeElements e recuperare il valore appropriato. Per ulteriori informazioni su come eseguire gli esempi, vedere Procedura: compilare ed eseguire gli esempi di codice del modello a oggetti di automazione.

Codice

[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

L'impostazione delle proprietà di elementi figlio dell'elemento del modello di codice non rileva tale comportamento. Solo le proprietà che influiscono direttamente sul CodeElement, quali il nome dell'elemento, il tipo di una funzione, la firma di un metodo e così via, rivelano tale comportamento non deterministico.

Inoltre, tale esempio è valido solamente se il nuovo nome del CodeElement è univoco tra gli elementi di pari livello. Ciò è dovuto al fatto che la proprietà Item restituisce il primo risultato, non utilizzabile per metodi/proprietà in overload, classi parziali o spazi dei nomi con lo stesso nome.

Vedere anche

Attività

Procedura: compilare codice di esempio per l'Extensibility del modello di codice di Visual C++

Procedura: creare un componente aggiuntivo

Procedura dettagliata: creazione di una procedura guidata

Procedura: modificare il codice tramite il modello di codice di Visual C++ (Visual C#)

Procedura: modificare il codice tramite il modello di codice di Visual C++ (Visual Basic)

Concetti

Individuazione di codice mediante il modello di codice (Visual Basic)

Modello di codice Visual C++

Grafico del modello a oggetti di automazione

Altre risorse

Creazione e controllo delle finestre di ambiente

Creazione di componenti aggiuntivi e di procedure guidate

Riferimenti su Extensibility e automazione