Equivalente VB.NET per C # ‘dinamico’ con Option Strict On

Esiste un equivalente per la parola chiave “dynamic” C # 4 quando si utilizza il tipo sicuro VB.NET, ovvero con Option Strict On ?

L’equivalente è Object in VB.NET ma con Option Strict Off . Con Option Strict On non c’è equivalente. In altre parole, la parola chiave dynamic porta Option Strict Off funzionalità equivalenti a C #.

VB.NET aveva sempre la funzione “dynamic” incorporata, originariamente chiamata late binding. Questa syntax è stata supportata per sempre:

  Dim obj = new SomeComClass() obj.DoSomething() 

Funzionava sul codice implementato in .NET e COM, essendo quest’ultimo l’uso più comune. La parola chiave dynamic in C # ha dato quella stessa capacità. È stato modificato in VB.NET versione 10, tuttavia ora utilizza anche il DLR. Che aggiunge il supporto per l’associazione dynamic alle implementazioni linguistiche come Python e Ruby.

La syntax è esattamente la stessa, usa la parola chiave Dim senza As. Dovrai comunque usare Option Strict Off, Option Infer On può ammorbidire un po ‘quel colpo. Mostra che C # usando una parola chiave specifica per segnalare l’associazione dynamic era una mossa abbastanza buona. Anche tutte le richieste di farlo in VB.NET sono state ancora prese in considerazione ma non pianificate.

Se si preferisce Option Strict On, quindi utilizzare la parola chiave Partial Class in modo da poter spostare parte del codice in un altro file sorgente è probabilmente l’approccio più efficace.

Ciò dimostrerà ciò che Basic sta dicendo su VB che non ha la stessa granularità in questo come C #. Ho questo pezzo di codice in C #, che usa la reflection per invocare dynamicmente un metodo in fase di runtime:

 var listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, null); 

La ragione per cui sto facendo questo è che “GetSomeData” potrebbe essere uno dei tanti metodi, ognuno dei quali riceve dati diversi. Quale metodo invocare qui dipende da un parametro stringa passato in questo object in fase di runtime, quindi il valore di “GetSomeData” varia in fase di esecuzione.

La firma di “GetSomeData” è:

 public List GetSomeData() 

Ciascuno dei metodi richiamati restituisce una specie di object List . Successivamente, invierò l’object listResult a un metodo generico chiamato Export, che assomiglia a questo:

 void Export(List exportList, string filePath, byte fileType) where T: class; 

Qui è dove ci imbattiamo in un problema. Invoke restituisce un object di tipo System.Object. Ovviamente, un List è anche un System.Object, ma l’interfaccia esposta è l’interfaccia System.Object, non l’interfaccia IList. Se provo ad eseguire il metodo Export, quindi:

 myExportObj.Export(listResult, parms.filePath, parms.fileType); 

il codice non riesce a compilare. L’errore è:

The type arguments for method '...Export...' cannot be inferred from the usage. Try specifying the type arguments explicitly.

No grazie!! Il problema è che il compilatore non riesce a trovare i metadati IList, perché sta esaminando l’interfaccia System.Object. Ora puoi creare una nuova List , assegnare (List) listResult ad essa, ma in primo luogo sconfigge lo scopo dell’invocazione dynamic.

La correzione è di cambiare var in dynamic :

 dynamic listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, null); 

Dal momento che la dynamic ignora il controllo del tipo statico in fase di compilazione, non si ottiene un errore di compilazione. Quindi, quando l’object dinamico viene passato al metodo Export, il DLR (Dynamic Language Runtime) controlla se può eseguire il cast implicito dell’object per soddisfare i requisiti della firma del metodo. Che, naturalmente, può

Ok, ecco come funzionano le cose in C #. Con VB, la linea va così:

 Dim listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, Nothing) 

Con Option Strict On, questa linea sconvolge il compilatore, come previsto. Con esso spento, funziona bene. In altre parole, in VB, devo distriggersre il controllo del tipo per l’intero modulo che contiene la linea. Non c’è granularità più fine di quella.

Puoi triggersre Option Infer On e Option Strict Off e avere ancora qualcosa di molto vicino.

Esistono modi sufficienti per gestire metodi e proprietà con gli oggetti COM di binding tardivo e digitare safe ( Option Strict On ). Questo quando si utilizzano i metodi Microsoft.VisualBasic.Interaction.CallByName e System.Type.InvokeMember. (O creare un file “parziale” separato dove Option Strict è Off ).

Ma per gestire gli eventi con l’associazione tardiva da VB.NET non è così semplice come con il tipo dinamico in C #. Puoi controllare “hack” per quello in Eventi dinamici in VB.NET .

Sì, ExpandoObject.

Dim DObj = New System.Dynamic.ExpandoObject ()

DObj.A = “abc”

DObj.B = 123

Nota che anche con Option Strict puoi ancora utilizzare ad esempio un ExpandoObject per accedere a proprietà come:

 Dim doc = JsonConvert.DeserializeObject(Of ExpandoObject)("{""name"":""Bob""}") Dim lookup as IDictionary(Of String, Object) = doc lookup("name") ' Bob 

L’equivalente della parola chiave dynamic c # in Vb.Net con opzione strict on esiste come pacchetto NuGet: Dynamitey.

Dopo il pacchetto di installazione Dynamitey, si può scrivere il codice Vb.Net come segue:

 Option Strict On : Option Infer On : Option Explicit On Imports Dynamitey Module Module1 Public Sub Main() Dim o = Nothing o = "1234567890" Console.WriteLine(Dynamic.InvokeMember(o, "Substring", 5)) ' writes 67890 End Sub End Module 

O il leggermente più leggibile:

 Option Strict On : Option Infer On : Option Explicit On Imports Dynamitey Module Module1  Public Function Substring(self As Object, offset As Integer) As String Return CType(Dynamic.InvokeMember(self, "Substring", offset), String) End Function Public Sub Main() Dim o = Nothing o = "1234567890" Console.WriteLine(Substring(o, 5)) ' writes 67890 End Sub End Module 

Testato con VS2017 e .net Framework 4.7.2.