web-dev-qa-db-de.com

VB.NET-Äquivalent für C # 'dynamisch' mit Option Strict On

Gibt es ein Äquivalent für das "dynamische" Schlüsselwort von C # 4, wenn Sie typsicher VB.NET verwenden, d. H. Mit Option Strict On?

69
jeroenh

Das Äquivalent ist Object in VB.NET, jedoch mit Option Strict Off. Mit Option Strict On gibt es keine Entsprechung. Anders ausgedrückt: Das Schlüsselwort dynamic bringt Option Strict Off-äquivalente Funktionen in C #.

51
Darin Dimitrov

VB.NET hatte immer die "dynamische" Funktion eingebaut, die ursprünglich als Late Binding bezeichnet wurde. Diese Syntax wurde für immer unterstützt:

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

Arbeitete mit Code, der in .NET und COM implementiert wurde, wobei letzteres die häufigste Verwendung fand. Das Schlüsselwort dynamic in C # hat dieselbe Funktion. Es wurde in VB.NET Version 10 geändert, verwendet jedoch jetzt auch den DLR. Die Unterstützung für dynamisches Binden an Sprachimplementierungen wie Python und Ruby wird hinzugefügt.

Die Syntax ist genau dieselbe, verwenden Sie das Dim-Schlüsselwort ohne As. Sie müssen jedoch die Option Strict Off verwenden, mit der Option Infer On können Sie den Schlag ein wenig mildern. Es zeigt sich jedoch, dass C # mit einem bestimmten Schlüsselwort für dynamische Bindung ein ziemlich guter Schritt war. Afaik alle Anträge, dies auch in VB.NET zu tun, wurden bisher berücksichtigt, aber nicht geplant.

Wenn Sie Option Strict On bevorzugen und dann das Schlüsselwort Partial Class verwenden, um einen Teil des Codes in eine andere Quelldatei zu verschieben, ist dies wahrscheinlich der effektivste Ansatz.

38
Hans Passant

Dies wird zeigen, was Basic sagt, dass VB nicht die gleiche Granularität wie C # hat. Ich habe diesen Code in C #, der Reflektion verwendet, um eine Methode zur Laufzeit dynamisch aufzurufen:

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

Der Grund, warum ich das mache, ist, dass "GetSomeData" eine von mehreren Methoden sein kann, von denen jede unterschiedliche Daten erhält. Welche Methode hier aufgerufen werden muss, hängt von einem String-Parameter ab, der zur Laufzeit an dieses Objekt übergeben wird. Daher variiert der Wert von "GetSomeData" zur Laufzeit. 

Die Signatur von "GetSomeData" lautet:

public List<SomeResultSetClass> GetSomeData()

Jede der aufgerufenen Methoden gibt eine Art von List<T>-Objekt zurück. Als nächstes sende ich das listResult-Objekt an eine generische Methode namens Export, die wie folgt aussieht:

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

Hier stoßen wir auf ein Problem. Invoke gibt ein Objekt vom Typ System.Object zurück. Natürlich ist ein List<T> auch ein System.Object, aber die offengelegte Schnittstelle ist die System.Object-Schnittstelle, nicht die IList-Schnittstelle. Wenn ich versuche, die Export-Methode auszuführen, gilt Folgendes:

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

der Code kann nicht kompiliert werden. Der Fehler ist:

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

Nein Danke!! Das Problem ist, dass der Compiler die IList-Metadaten nicht finden kann, da er die System.Object-Schnittstelle betrachtet. Jetzt können Sie einen neuen List<T> erstellen und ihm (List<Whatever>) listResult zuweisen, was jedoch den Zweck des dynamischen Aufrufs in erster Linie vereitelt. 

Das Update besteht darin, var in dynamic zu ändern:

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

Da die dynamische Überprüfung statischer Typen zur Kompilierzeit umgeht, wird kein Kompilierungsfehler angezeigt. Wenn das dynamische Objekt an die Export-Methode übergeben wird, prüft die DLR (Dynamic Language Runtime), ob das Objekt implizit umgewandelt werden kann, um die Anforderungen der Methodensignatur zu erfüllen. Was kann es natürlich.

Ok, so funktionieren die Dinge in C #. Mit VB geht die Linie so:

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

Mit Option Strict On stellt diese Zeile den Compiler wie erwartet auf den Kopf. Wenn es ausgeschaltet ist, funktioniert es gut. Mit anderen Worten, in VB muss ich den Typprüfer für das gesamte Modul deaktivieren, das die Zeile enthält. Es gibt keine feinere Granularität.

6
BobRodes

Sie können Option Infer ein und Option Strict ausschalten und haben dennoch etwas in der Nähe.

3
Joel Coehoorn

Es gibt genügend Möglichkeiten, Methoden und Eigenschaften mit spät gebundenen COM-Objekten und dem Typ safe (Option Strict On) zu behandeln. Dies bei Verwendung der Methoden Microsoft.VisualBasic.Interaction.CallByName und System.Type.InvokeMember. (Oder erstellen Sie eine separate "partielle" Datei, wobei Option StrictOff ist).

Ereignisse mit spätem Binding von VB.NET zu behandeln, ist jedoch nicht so einfach wie mit dem dynamischen Typ in C #. Sie können den "Hack" in Dynamic Events in VB.NET überprüfen.

1
Vozzie

Das Äquivalent des dynamischen Schlüsselworts c # in Vb.Net mit der Option strict ist als NuGet-Paket vorhanden: Dynamitey.

Nach dem Installationspaket Dynamitey kann Vb.Net-Code wie folgt geschrieben werden:

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

Oder das etwas lesbarer:

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

Getestet mit VS2017 und .net Framework 4.7.2.

0

Beachten Sie, dass Sie selbst mit Option Strict noch z. ein ExpandoObject für den Zugriff auf Eigenschaften wie:

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

Ja, ExpandoObject.

Dim DObj = Neues System.Dynamic.ExpandoObject ()

DObj.A = "abc"

DObj.B = 123

0
Doron Saar