Эквивалент VB.NET для С# 'dynamic' с опцией Strict On

Существует ли эквивалент для ключевого слова С# 4 'dynamic' при использовании безопасного типа VB.NET, т.е. с Option Strict On?

Ответ 1

Эквивалент - объект в VB.NET, но с Option Strict Off. При Option Strict On нет эквивалента. Другими словами, ключевое слово dynamic приносит Option Strict Off эквивалентную функциональность С#.

Ответ 2

У VB.NET всегда была встроенная "динамическая" функция, первоначально называвшаяся поздней привязкой. Этот синтаксис поддерживался навсегда:

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

Работает над кодом, реализованным в .NET и COM, причем последнее является наиболее распространенным. Динамическое ключевое слово в С# дало ему такую ​​же возможность. Однако он изменился в версии VB.NET версии 10, но теперь он использует DLR. Что добавляет поддержку динамической привязки к языковым реализациям, таким как Python и Ruby.

Синтаксис точно такой же, используйте ключевое слово Dim без As. Однако вам придется использовать опцию Strict Off, Option Infer On, которая может немного смягчить этот удар. Это показывает, что С#, использующее конкретное ключевое слово для динамического связывания сигнала, было довольно хорошим шагом. Afaik все запросы сделать это в VB.NET также пока не рассмотрены, но не запланированы.

Если вы предпочитаете вариант Strict On, то с использованием ключевого слова Partial Class, чтобы вы могли переместить часть кода в другой исходный файл, вероятно, наиболее эффективный подход.

Ответ 3

Это продемонстрирует, что Basic говорит о том, что VB не имеет такой же степени детализации в этом, как С#. У меня есть эта часть кода на С#, которая использует отражение для динамического вызова метода во время выполнения:

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

Причина, по которой я делаю это, заключается в том, что "GetSomeData" может быть любым из нескольких методов, каждый из которых получает разные данные. Какой метод для вызова здесь зависит от параметра строки, переданного в этот объект во время выполнения, поэтому значение "GetSomeData" изменяется во время выполнения.

Подпись "GetSomeData" :

public List<SomeResultSetClass> GetSomeData()

Каждый из вызванных методов возвращает какой-то объект List<T>. Затем я отправляю объект listResult в общий метод Export, который выглядит следующим образом:

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

Здесь мы сталкиваемся с проблемой. Invoke возвращает объект типа System.Object. Конечно, List<T> также является объектом System.Object, но интерфейсом является интерфейс System.Object, а не интерфейс IList. Если я попытаюсь выполнить метод Export, таким образом:

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

код не скомпилируется. Ошибка:

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

Нет, спасибо! Проблема в том, что компилятор не может найти метаданные IList, потому что он смотрит на интерфейс System.Object. Теперь вы можете создать новый List<T>, присвоить ему (List<Whatever>) listResult, но в первую очередь победите цель динамического вызова.

Исправление состоит в изменении var на dynamic:

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

Поскольку динамический обход проверки статического типа во время компиляции, мы не получаем ошибку компиляции. Затем, когда динамический объект передается методу "Экспорт", DLR (Dynamic Language Runtime) смотрит, может ли он неявно отбрасывать объект в соответствии с требованиями сигнатуры метода. Это, конечно, возможно.

Хорошо, так как все работает на С#. С VB строка выглядит следующим образом:

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

С опцией Strict On эта строка расстраивает компилятор, как и ожидалось. С его помощью он работает нормально. Другими словами, в VB мне нужно отключить проверку типа для всего модуля, который содержит строку. Нет более тонкой детализации, чем это.

Ответ 4

Вы можете включить опцию Infer On и Option Strict Off и все еще иметь что-то очень близкое.

Ответ 5

Существует достаточно способов обработки методов и свойств с поздними связями COM-объектов и безопасностью типа (Option Strict On). Это при использовании методов Microsoft.VisualBasic.Interaction.CallByName и System.Type.InvokeMember. (Или создайте отдельный "частичный" файл, где Option Strict есть Off).

Но обрабатывать события с поздним связыванием с VB.NET не так просто, как с динамическим типом в С#. Вы можете проверить "взломать" для этого в Динамические события в VB.NET.

Ответ 6

Да, ExpandoObject.

Dim DObj = Новая система .Dynamic.ExpandoObject()

DObj.A = "abc"

DObj.B = 123

Ответ 7

Обратите внимание, что даже с помощью опции Strict вы все равно можете использовать, например, ExpandoObject для доступа к таким свойствам, как:

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

Ответ 8

Эквивалент ключевого слова С# dynamic в Vb.Net с опцией strict on существует в виде пакета NuGet: Dynamitey.

После установки пакета Dynamitey можно записать код Vb.Net следующим образом:

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

Или немного более читаемым:

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

Протестировано с VS2017 и.net Framework 4.7.2.