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

77

Gibt es eine Entsprechung für das C # 4-Schlüsselwort 'dynamic', wenn typsicheres VB.NET verwendet wird, dh mit Option Strict On?

jeroenh
quelle
1
VB ist typsicher, unabhängig davon, ob Option Strict ein oder aus ist. Lesen Sie hier über die Bedeutung msdn.microsoft.com/en-us/library/hbzz1a9a(VS.80).aspx
John K
@jdk ok ich denke ich muss zustimmen. Wie ich vielleicht vermutet habe, meinte ich jedoch die zur Kompilierungszeit überprüfte
Typensicherheit
@jdk: Die Definition der Typensicherheit, die jeder verwendet, wenn er über Programmiersprachen spricht, ist diese: en.wikipedia.org/wiki/Type_safety
Mauricio Scheffer
1
@jeroenh Ich war inspiriert, einen Vorschlag auf Microsoft Connect zu veröffentlichen, dass es schön wäre, wenn VB so etwas wie dynamicin C # hätte. Jeder, der zustimmt oder nicht zustimmt, kann hier
abgeben
3
Der Microsoft VB-Spezifikationsleiter hat gerade über diese Idee gebloggt . Die vorläufige Bewertung des VB-Teams lautet: "VB hatte immer eine eigene Form der Spätbindung über Object. Obwohl es eine Schande ist, dass Sie Ihre Spätbindung nicht kleiner als die Dateigranularität festlegen können, scheint dies kein ausreichend großes Problem zu sein." eine zweite Form der Spätbindung zu rechtfertigen. " Sehr geehrter Leser, wenn Sie diesbezüglich ein starkes Gefühl haben, hinterlassen Sie doch einen Kommentar im Blog oder zum Microsoft Connect-Problem, das in meinem früheren Kommentar erwähnt wurde.
MarkJ

Antworten:

55

Das Äquivalent ist Object in VB.NET, aber mit Option Strict Off. Mit Option Strict Ongibt es kein Äquivalent. Anders ausgedrückt, das dynamische Schlüsselwort bringt esOption Strict Off C # äquivalente Funktionen.

Darin Dimitrov
quelle
5
Nur dass es nicht genau das gleiche ist. Zum Beispiel konnte ich nicht herausfinden, wie eine Methode (siehe stackoverflow.com/questions/17819977/… ) wie in C # dynamisch aufgerufen werden kann.
Pat
5
Das C # -Modell ermöglicht es Ihnen, eine Ausnahme für ein bestimmtes Objekt zu machen. Das VB-Modell zwingt Sie dazu, dies weitaus weniger detailliert zu tun
Basic
Ich weiß, dass es eine alte Frage ist, aber es gibt eine Möglichkeit, spät zu binden und Option Strict beizubehalten. In den Projekteigenschaften auf der Registerkarte Kompilieren können wir die späte Bindung auf "Keine" setzen (und Option Strict nimmt den Status "Benutzerdefiniert" an), um die späte Bindung in einer sichereren Umgebung durchzuführen, als sie auf Off zu setzen
Sehnsucht
1
Sie rufen eine Methode in vb.net für ein Objekt dynamisch auf, indem Sie es einfach aufrufen. Stellen Sie sicher, dass Sie natürlich Klammern einfügen.
Brain2000
CallByName - Sollte allen Websuchern da draußen
Ryanwebjackson
37

In VB.NET war immer die "dynamische" Funktion integriert, die ursprünglich als späte Bindung bezeichnet wurde. Diese Syntax wurde für immer unterstützt:

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

Arbeitete an Code, der in .NET und COM implementiert ist, wobei letzterer die häufigste Verwendung ist. Das dynamische Schlüsselwort in C # gab ihm die gleiche Fähigkeit. Es wurde in VB.NET Version 10 geändert, verwendet jetzt jedoch auch das DLR. Dies unterstützt Sprachimplementierungen wie Python und Ruby bei der dynamischen Bindung.

Die Syntax ist genau die gleiche. Verwenden Sie das Schlüsselwort Dim ohne As. Sie müssen jedoch Option Strict Off verwenden. Option Infer On kann diesen Schlag etwas mildern. Es zeigt, dass C # mit einem bestimmten Schlüsselwort zur Signalisierung der dynamischen Bindung ein ziemlich guter Schachzug war. Afaik alle Anfragen dazu auch in VB.NET wurden bisher berücksichtigt, aber nicht geplant.

Wenn Sie Option Strict On bevorzugen, ist die Verwendung des Schlüsselworts Partial Class, mit dem Sie einen Teil des Codes in eine andere Quelldatei verschieben können, wahrscheinlich der effektivste Ansatz.

Hans Passant
quelle
14
@ Hans Passant: Ich weiß, dass C # -Dynamik jedoch nicht ganz mit VBs 'Late Binding' identisch ist. In C # kann ich mit dem dynamischen Schlüsselwort die dynamischen Teile meines Programms sehr explizit beschreiben. Für mich ist es so, als würde man dem Compiler sagen: "Hey, ich weiß, was ich für diesen bestimmten Teil meines Programms mache." Mit VB.Net muss ich Option Strict für mein gesamtes Projekt deaktivieren, was dazu führen kann, dass sich subtile Fehler einschleichen.
Jeroenh
@Hans @jeroen. In Ihrem editierten Code, appwird als Typ abgeleitet Object, so ist es nicht möglich, verwenden Sie das Excel - Application - Objekt app. Wenn ich zum Beispiel ersetze, app.Calculatewo Sie es haben, wird REM etc...es nicht kompiliert. Ich denke, das ist das Problem, nach dem Jeroen fragt. Der Compiler sagtError 1 Option Strict On disallows late binding.
MarkJ
@ MarkJ - du hast absolut recht. Ich habe die Sprachspezifikation für VB.NET Version 10 überprüft, um sicherzugehen. Erstaunlicherweise wird das DLR nirgendwo erwähnt . Option Strict Off sieht völlig unvermeidlich aus. Ich entschuldige mich für die schlechte Antwort.
Hans Passant
1
Ich war inspiriert, einen Vorschlag auf Microsoft Connect zu veröffentlichen, dass VB so etwas haben sollte dynamic. Jeder, der stark zustimmt oder nicht zustimmt, kann hier
abgeben
11
@jeroenh Sie können die Optionen auf Projektebene auf Dateiebene mit verschiedenen OptionAnweisungen am Anfang der Datei überschreiben .
Mark Hurd
8

Dies zeigt, was Basic über VB sagt, das nicht die gleiche Granularität wie C # aufweist. Ich habe diesen Code in C #, der mithilfe der Reflektion eine Methode zur Laufzeit dynamisch aufruft:

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

Der Grund, warum ich das mache, ist, dass "GetSomeData" eine von mehreren Methoden sein kann, die jeweils unterschiedliche Daten erhalten. Welche Methode hier aufgerufen werden soll, hängt von einem Zeichenfolgenparameter 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 List<T>Objekt zurück. Als Nächstes sende ich das listResult-Objekt an eine generische Methode namens Export, die folgendermaßen 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 List<T>ist a auch ein System.Object, aber die offenbarte Schnittstelle ist die System.Object-Schnittstelle, nicht die IList-Schnittstelle. Wenn ich versuche, die Exportmethode 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 eine neue erstellen List<T>, ihr zuweisen (List<Whatever>) listResult, aber das macht den Zweck des dynamischen Aufrufs in erster Linie zunichte.

Das Update ist zu ändern varzu dynamic:

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

Da Dynamic die statische Typprüfung zur Kompilierungszeit umgeht, wird kein Kompilierungsfehler angezeigt. Wenn das dynamische Objekt an die Exportmethode übergeben wird, prüft das DLR (Dynamic Language Runtime), ob es das Objekt implizit umwandeln kann, um die Anforderungen der Methodensignatur zu erfüllen. Was es natürlich kann.

Ok, so funktionieren die Dinge in C #. Bei VB sieht die Linie folgendermaßen aus:

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

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

BobRodes
quelle
3

Sie können Option Infer On und Option Strict Off aktivieren und trotzdem etwas sehr Nahes haben.

Joel Coehoorn
quelle
1

Es gibt genügend Möglichkeiten, Methoden und Eigenschaften mit spät bindenden COM-Objekten zu verarbeiten und safe ( Option Strict On) einzugeben . Dies bei Verwendung der Methoden Microsoft.VisualBasic.Interaction.CallByName und System.Type.InvokeMember. (Oder erstellen Sie eine separate "partielle" Datei, wo sich Option Strictbefindet Off).

Die Behandlung von Ereignissen mit verspäteter Bindung von VB.NET ist jedoch nicht so einfach wie beim dynamischen Typ in C #. Sie können den "Hack" dafür in Dynamic Events in VB.NET überprüfen .

Vozzie
quelle
1

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

Nach dem Installationspaket Dynamitey kann man Vb.Net-Code wie folgt schreiben:

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 besser lesbare:

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.

Wolfgang Grinfeld
quelle
0

Ja, ExpandoObject.

Dim DObj = Neues System.Dynamic.ExpandoObject ()

DObj.A = "abc"

DObj.B = 123

Doron Saar
quelle
1
Das ExpandoObject scheint ein IDictionary (Of string, object) unter der Haube zu verwenden. Interessant.
Brain2000
1
Die Frage fragt, wie es geht Option Strict On. Ihre Antwort funktioniert nur mitOption Strict Off
Nick
0

Beachten Sie, dass Sie auch bei aktivierter Option Strict z. B. ein ExpandoObject verwenden können, um auf Eigenschaften wie Folgendes zuzugreifen:

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