web-dev-qa-db-fra.com

Équivalent VB.NET pour C # 'dynamic' avec Option Strict On

Existe-t-il un équivalent pour le mot clé "dynamique" C # 4 lorsqu’on utilise le type safe VB.NET, c’est-à-dire avec Option Strict On?

69
jeroenh

L'équivalent est Object dans VB.NET mais avec Option Strict Off. Avec Option Strict On, il n'y a pas d'équivalent. En d'autres termes, le mot-clé dynamic apporte une fonctionnalité Option Strict Off équivalente à C #.

51
Darin Dimitrov

VB.NET a toujours eu la fonctionnalité "dynamique" intégrée, appelée à l'origine liaison tardive. Cette syntaxe a été supportée pour toujours:

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

Travaillé sur le code implémenté dans .NET et COM, ce dernier étant l'utilisation la plus courante. Le mot clé dynamic en C # lui a donné la même capacité. Il a été modifié dans VB.NET version 10, cependant, il utilise maintenant le DLR également. Ce qui ajoute la prise en charge de la liaison dynamique aux implémentations de langage telles que Python et Ruby.

La syntaxe est exactement la même, utilisez le mot-clé Dim sans As. Vous devrez cependant utiliser Option Strict Off, Option Infer On peut atténuer un peu ce coup. Cela montre que C # utilisant un mot clé spécifique pour signaler la liaison dynamique était un très bon coup. Toutes les demandes en ce sens dans VB.NET ont également été prises en compte mais n’avaient pas été planifiées.

Si vous préférez Option Strict On, utiliser le mot-clé Partial Class pour déplacer une partie du code dans un autre fichier source est probablement l'approche la plus efficace.

38
Hans Passant

Cela démontrera ce que dit Basic sur le fait que VB n’ait pas la même granularité en ce sens que C #. J'ai ce morceau de code en C #, qui utilise la réflexion pour invoquer dynamiquement une méthode au moment de l'exécution:

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

La raison pour laquelle je fais ceci est que "GetSomeData" pourrait être une méthode parmi un certain nombre de méthodes, chacune obtenant des données différentes. La méthode à appeler ici dépend d'un paramètre de chaîne transmis à cet objet lors de l'exécution. La valeur de "GetSomeData" varie lors de l'exécution. 

La signature de "GetSomeData" est:

public List<SomeResultSetClass> GetSomeData()

Chacune des méthodes invoquées renvoie une sorte d'objet List<T>. Ensuite, j'envoie l'objet listResult à une méthode générique appelée Export, qui ressemble à ceci:

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

Voici où nous rencontrons un problème. Invoke renvoie un objet de type System.Object. Bien sûr, un List<T> est également un System.Object, mais l'interface exposée est l'interface System.Object, pas l'interface IList. Si j'essaye d'exécuter la méthode Export, alors:

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

le code ne parvient pas à se compiler. L'erreur est:

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

Non merci!! Le problème est que le compilateur ne peut pas trouver les métadonnées IList, car il regarde l'interface System.Object. Maintenant, vous pouvez créer un nouveau List<T>, lui assigner (List<Whatever>) listResult, mais cela va à l’encontre du but de l’appel dynamique. 

Le correctif consiste à changer var en dynamic:

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

Puisque Dynamic contourne la vérification de type statique lors de la compilation, nous n’obtenons pas d’erreur de compilation. Ensuite, lorsque l'objet dynamique est passé à la méthode Export, le DLR (Dynamic Language Runtime) vérifie s'il peut implicitement transtyper l'objet pour répondre aux exigences de la signature de la méthode. Ce qui bien sur peut.

Ok, c'est comme ça que les choses fonctionnent en C #. Avec VB, la ligne va comme ceci:

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

Avec Option Strict On, cette ligne bouleverse le compilateur, comme prévu. Avec ça, ça marche bien. En d'autres termes, en VB, je dois désactiver le vérificateur de type pour tout le module contenant la ligne. Il n'y a pas de granularité plus fine que cela.

6
BobRodes

Vous pouvez activer Option Infer et Option Strict Off tout en conservant un élément très proche.

3
Joel Coehoorn

Il existe suffisamment de façons de gérer les méthodes et les propriétés avec des objets COM de liaison tardive et de taper safe (Option Strict On). Cela lors de l'utilisation des méthodes Microsoft.VisualBasic.Interaction.CallByName et System.Type.InvokeMember. (Ou créez un fichier "partiel" séparé où Option Strict est Off).

Mais gérer des événements avec une liaison tardive à partir de VB.NET n'est pas aussi simple qu'avec le type dynamique en C #. Vous pouvez vérifier le "hack" pour cela dans Evénements dynamiques dans VB.NET.

1
Vozzie

L'équivalent du mot clé dynamique c # dans Vb.Net avec l'option strict est présent sous forme de package NuGet: Dynamitey.

Après avoir installé Dynamitey, vous pouvez écrire le code Vb.Net de la manière suivante:

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

Ou le légèrement plus lisible:

Option Strict On : Option Infer On : Option Explicit On
Imports Dynamitey
Module Module1
    <Extension()>
    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

Testé avec VS2017 et .net Framework 4.7.2.

0
Wolfgang Grinfeld

Notez que même avec Option Strict, vous pouvez toujours utiliser, par exemple. un ExpandoObject pour accéder à des propriétés telles que:

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

Oui, ExpandoObject.

Dim DObj = New System.Dynamic.ExpandoObject ()

DObj.A = "abc"

DObj.B = 123

0
Doron Saar