Procedura dettagliata: Creazione e utilizzo di oggetti dinamici in Visual Basic

Gli oggetti dinamici espongono i membri, ad esempio proprietà e metodi, in fase di esecuzione anziché in fase di compilazione. In questo modo è possibile creare oggetti da usare con le strutture che non corrispondono a un tipo o formato statico. Ad esempio, è possibile usare un oggetto dinamico per fare riferimento al modello a oggetti documenti (DOM, Document Object Model) HTML, che può contenere qualsiasi combinazione di attributi ed elementi di markup HTML validi. Poiché ogni documento HTML è univoco, i membri per un particolare documento HTML vengono determinati in fase di esecuzione. Un metodo comune per fare riferimento a un attributo di un elemento HTML consiste nel passare il nome dell'attributo al metodo GetProperty dell'elemento. Per fare riferimento all'attributo id dell'elemento HTML <div id="Div1">, per prima cosa è necessario ottenere un riferimento all'elemento <div> e quindi usare divElement.GetProperty("id"). Se si usa un oggetto dinamico, è possibile fare riferimento all'attributo id come divElement.id.

Gli oggetti dinamici offrono anche un comodo accesso a linguaggi dinamici come IronPython e IronRuby. È possibile usare un oggetto dinamico per fare riferimento a uno script dinamico che viene interpretato in fase di esecuzione.

Si fa riferimento a un oggetto dinamico usando l'associazione tardiva. Il tipo di un oggetto ad associazione tardiva viene specificato come Object. Per altre informazioni, vedere Associazione anticipata e tardiva.

È possibile creare oggetti dinamici personalizzati usando le classi dello spazio dei nomi System.Dynamic. Ad esempio, è possibile creare un oggetto ExpandoObject e specificare i membri di tale oggetto in fase di esecuzione. È anche possibile creare un proprio tipo che eredita la classe DynamicObject. È quindi possibile eseguire l'override dei membri della classe DynamicObject per rendere disponibili funzionalità dinamiche in fase di esecuzione.

Questo articolo contiene due procedure dettagliate indipendenti:

  • Creare un oggetto personalizzato che espone dinamicamente il contenuto di un file di testo come proprietà di un oggetto.

  • Creare un progetto che usa una libreria IronPython.

È possibile eseguire una o entrambe queste procedure dettagliate e, se si eseguono entrambe, l'ordine non è rilevante.

Prerequisiti

Nota

I nomi o i percorsi visualizzati per alcuni elementi dell'interfaccia utente di Visual Studio nelle istruzioni seguenti potrebbero essere diversi nel computer in uso. La versione di Visual Studio in uso e le impostazioni configurate determinano questi elementi. Per altre informazioni, vedere Personalizzazione dell'IDE.

  • Per la seconda procedura dettagliata, installare IronPython per .NET. Passare alla pagina di download per ottenere la versione più recente.

Creare un oggetto dinamico personalizzato

La prima procedura dettagliata definisce un oggetto dinamico personalizzato che esegue la ricerca del contenuto di un file di testo. Una proprietà dinamica specifica il testo da cercare. Ad esempio, se il codice chiamante specifica dynamicFile.Sample, la classe dinamica restituisce un elenco generico di stringhe che contiene tutte le righe del file che iniziano con "Sample". La ricerca non fa distinzione tra maiuscole e minuscole. La classe dinamica supporta inoltre due argomenti facoltativi. Il primo argomento è un valore di enumerazione dell'opzione di ricerca che indica che la classe dinamica deve cercare le corrispondenze all'inizio della riga, alla fine della riga o in un punto qualsiasi nella riga. Il secondo argomento specifica che la classe dinamica deve eliminare gli spazi iniziali e finali da ogni riga prima di eseguire la ricerca. Ad esempio, se il codice chiamante specifica dynamicFile.Sample(StringSearchOption.Contains), la classe dinamica cerca "Sample" in qualsiasi punto di una riga. Se il codice chiamante specifica dynamicFile.Sample(StringSearchOption.StartsWith, false), la classe dinamica cerca "Sample" all'inizio di ogni riga e non rimuove gli spazi iniziali e finali. Il comportamento predefinito della classe dinamica è cercare una corrispondenza all'inizio di ogni riga e rimuovere gli spazi iniziali e finali.

Per creare una classe dinamica personalizzata

  1. Avviare Visual Studio.

  2. Selezionare Crea un nuovo progetto.

  3. Nella finestra di dialogo Crea un nuovo progetto selezionare Visual Basic, quindi Applicazione console e infine Avanti.

  4. Nella finestra di dialogo Configura il nuovo progetto immettere DynamicSample in Nome progetto e quindi selezionare Avanti.

  5. Nella finestra di dialogo Informazioni aggiuntive selezionare .NET 5.0 (corrente) per Framework di destinazione e quindi selezionare Crea.

    Viene creato il nuovo progetto.

  6. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto DynamicSample e selezionare Aggiungi>Classe. Nella casella Nome digitare ReadOnlyFile e quindi selezionare Aggiungi.

    Viene aggiunto un nuovo file che contiene la classe ReadOnlyFile.

  7. Nella parte superiore del file ReadOnlyFile.cs o ReadOnlyFile.vb aggiungere il codice seguente per importare gli spazi dei nomi System.IO e System.Dynamic.

    Imports System.IO
    Imports System.Dynamic
    
  8. L'oggetto dinamico personalizzato usa un'enumerazione per determinare i criteri di ricerca. Prima dell'istruzione di classe, aggiungere la seguente definizione di enumerazione.

    Public Enum StringSearchOption
        StartsWith
        Contains
        EndsWith
    End Enum
    
  9. Aggiornare la dichiarazione di classe per ereditare la classe DynamicObject, come illustrato nell'esempio di codice seguente.

    Public Class ReadOnlyFile
        Inherits DynamicObject
    
  10. Aggiungere il codice seguente alla classe ReadOnlyFile per definire un campo privato per il percorso del file e un costruttore per la classe ReadOnlyFile.

    ' Store the path to the file and the initial line count value.
    Private p_filePath As String
    
    ' Public constructor. Verify that file exists and store the path in 
    ' the private variable.
    Public Sub New(ByVal filePath As String)
        If Not File.Exists(filePath) Then
            Throw New Exception("File path does not exist.")
        End If
    
        p_filePath = filePath
    End Sub
    
  11. Aggiungere il seguente metodo GetPropertyValue alla classe ReadOnlyFile. Il metodo GetPropertyValue accetta come input i criteri di ricerca e restituisce le righe di un file di testo che soddisfano tali criteri di ricerca. I metodi dinamici specificati dalla classe ReadOnlyFile chiamano il metodo GetPropertyValue per recuperare i rispettivi risultati.

    Public Function GetPropertyValue(ByVal propertyName As String,
                                     Optional ByVal StringSearchOption As StringSearchOption = StringSearchOption.StartsWith,
                                     Optional ByVal trimSpaces As Boolean = True) As List(Of String)
    
        Dim sr As StreamReader = Nothing
        Dim results As New List(Of String)
        Dim line = ""
        Dim testLine = ""
    
        Try
            sr = New StreamReader(p_filePath)
    
            While Not sr.EndOfStream
                line = sr.ReadLine()
    
                ' Perform a case-insensitive search by using the specified search options.
                testLine = UCase(line)
                If trimSpaces Then testLine = Trim(testLine)
    
                Select Case StringSearchOption
                    Case StringSearchOption.StartsWith
                        If testLine.StartsWith(UCase(propertyName)) Then results.Add(line)
                    Case StringSearchOption.Contains
                        If testLine.Contains(UCase(propertyName)) Then results.Add(line)
                    Case StringSearchOption.EndsWith
                        If testLine.EndsWith(UCase(propertyName)) Then results.Add(line)
                End Select
            End While
        Catch
            ' Trap any exception that occurs in reading the file and return Nothing.
            results = Nothing
        Finally
            If sr IsNot Nothing Then sr.Close()
        End Try
    
        Return results
    End Function
    
  12. Dopo il metodo GetPropertyValue aggiungere il codice seguente per eseguire l'override del metodo TryGetMember della classe DynamicObject. Il metodo TryGetMember viene chiamato quando viene richiesto un membro di una classe dinamica e non vengono specificati argomenti. L'argomento binder contiene informazioni relative al membro a cui viene fatto riferimento e l'argomento result fa riferimento al risultato restituito per il membro specificato. Il metodo TryGetMember restituisce un valore booleano che restituisce true se il membro richiesto esiste, altrimenti restituisce false.

    ' Implement the TryGetMember method of the DynamicObject class for dynamic member calls.
    Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
                                           ByRef result As Object) As Boolean
        result = GetPropertyValue(binder.Name)
        Return If(result Is Nothing, False, True)
    End Function
    
  13. Dopo il metodo TryGetMember aggiungere il codice seguente per eseguire l'override del metodo TryInvokeMember della classe DynamicObject. Il metodo TryInvokeMember viene chiamato quando viene richiesto un membro di una classe dinamica con argomenti. L'argomento binder contiene informazioni relative al membro a cui viene fatto riferimento e l'argomento result fa riferimento al risultato restituito per il membro specificato. L'argomento args contiene una matrice degli argomenti passati al membro. Il metodo TryInvokeMember restituisce un valore booleano che restituisce true se il membro richiesto esiste, altrimenti restituisce false.

    La versione personalizzata del metodo TryInvokeMember prevede che il primo argomento sia un valore dell'enumerazione StringSearchOption definita in un passaggio precedente. Il metodo TryInvokeMember prevede che il secondo argomento sia un valore booleano. Se uno o entrambi gli argomenti sono valori validi, vengono passati al metodo GetPropertyValue per recuperare i risultati.

    ' Implement the TryInvokeMember method of the DynamicObject class for 
    ' dynamic member calls that have arguments.
    Public Overrides Function TryInvokeMember(ByVal binder As InvokeMemberBinder,
                                              ByVal args() As Object,
                                              ByRef result As Object) As Boolean
    
        Dim StringSearchOption As StringSearchOption = StringSearchOption.StartsWith
        Dim trimSpaces = True
    
        Try
            If args.Length > 0 Then StringSearchOption = CType(args(0), StringSearchOption)
        Catch
            Throw New ArgumentException("StringSearchOption argument must be a StringSearchOption enum value.")
        End Try
    
        Try
            If args.Length > 1 Then trimSpaces = CType(args(1), Boolean)
        Catch
            Throw New ArgumentException("trimSpaces argument must be a Boolean value.")
        End Try
    
        result = GetPropertyValue(binder.Name, StringSearchOption, trimSpaces)
    
        Return If(result Is Nothing, False, True)
    End Function
    
  14. Salva e chiudi il file.

Per creare un file di testo di esempio

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto DynamicSample e scegliere Aggiungi>Nuovo elemento. Nel riquadro Modelli installati selezionare Generale, quindi il modello File di testo. Non modificare il nome predefinito TextFile1.txt nella casella Nome e quindi fare clic su Aggiungi. Un nuovo file di testo viene aggiunto al progetto.

  2. Copiare il testo seguente nel file TextFile1.txt.

    List of customers and suppliers
    
    Supplier: Lucerne Publishing (https://www.lucernepublishing.com/)
    Customer: Preston, Chris
    Customer: Hines, Patrick
    Customer: Cameron, Maria
    Supplier: Graphic Design Institute (https://www.graphicdesigninstitute.com/)
    Supplier: Fabrikam, Inc. (https://www.fabrikam.com/)
    Customer: Seubert, Roxanne
    Supplier: Proseware, Inc. (http://www.proseware.com/)
    Customer: Adolphi, Stephan
    Customer: Koch, Paul
    
  3. Salva e chiudi il file.

Per creare un'applicazione di esempio che usa l'oggetto dinamico personalizzato

  1. In Esplora soluzioni fare doppio clic sul file Program.vb.

  2. Aggiungere il seguente codice alla routine Main per creare un'istanza della classe ReadOnlyFile per il file TextFile1.txt. Il codice usa l'associazione tardiva per chiamare i membri dinamici e recuperare le righe di testo che contengono la stringa "Customer".

    Dim rFile As Object = New ReadOnlyFile("..\..\..\TextFile1.txt")
    For Each line In rFile.Customer
        Console.WriteLine(line)
    Next
    Console.WriteLine("----------------------------")
    For Each line In rFile.Customer(StringSearchOption.Contains, True)
        Console.WriteLine(line)
    Next
    
  3. Salvare il file e premere CTRL+F5 per compilare ed eseguire l'applicazione.

Chiamare una libreria di linguaggio dinamico

La procedura dettagliata seguente consente di creare un progetto che accede a una libreria scritta nel linguaggio dinamico IronPython.

Per creare una classe dinamica personalizzata

  1. In Visual Studio selezionare File>Nuovo>Progetto.

  2. Nella finestra di dialogo Crea un nuovo progetto selezionare Visual Basic, quindi Applicazione console e infine Avanti.

  3. Nella finestra di dialogo Configura il nuovo progetto immettere DynamicIronPythonSample in Nome progetto e quindi selezionare Avanti.

  4. Nella finestra di dialogo Informazioni aggiuntive selezionare .NET 5.0 (corrente) per Framework di destinazione e quindi selezionare Crea.

    Viene creato il nuovo progetto.

  5. Installare il pacchetto NuGet IronPython.

  6. Modificare il file Program.vb.

  7. Nella parte superiore del file aggiungere il codice seguente per importare gli spazi dei nomi Microsoft.Scripting.Hosting e IronPython.Hosting dalle librerie IronPython e lo spazio dei nomi System.Linq.

    Imports Microsoft.Scripting.Hosting
    Imports IronPython.Hosting
    Imports System.Linq
    
  8. Nel metodo Main aggiungere il codice seguente per creare un nuovo oggetto Microsoft.Scripting.Hosting.ScriptRuntime per ospitare le librerie di IronPython. L'oggetto ScriptRuntime carica il modulo di libreria random.py di IronPython.

    ' Set the current directory to the IronPython libraries.
    System.IO.Directory.SetCurrentDirectory(
        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) &
           "\IronPython 2.7\Lib")
    
    ' Create an instance of the random.py IronPython library.
    Console.WriteLine("Loading random.py")
    Dim py = Python.CreateRuntime()
    Dim random As Object = py.UseFile("random.py")
    Console.WriteLine("random.py loaded.")
    
  9. Dopo il codice che carica il modulo random.py, aggiungere il codice seguente per creare una matrice di numeri interi. La matrice viene passata al metodo shuffle del modulo random.py, che ordina i valori nella matrice in modo casuale.

    ' Initialize an enumerable set of integers.
    Dim items = Enumerable.Range(1, 7).ToArray()
    
    ' Randomly shuffle the array of integers by using IronPython.
    For i = 0 To 4
        random.shuffle(items)
        For Each item In items
            Console.WriteLine(item)
        Next
        Console.WriteLine("-------------------")
    Next
    
  10. Salvare il file e premere CTRL+F5 per compilare ed eseguire l'applicazione.

Vedi anche