Проблема объявления анонимного метода с помощью vb.net Action (Of T) и lambda - PullRequest
2 голосов
/ 22 апреля 2009
Imports System.Reflection
Public Class Test
    Private Field As String
End Class

Module Module1
    Sub Main()

        Dim field = GetType(Test).GetField("Field", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)

        Dim test = New Test

        Dim GetValue = New Func(Of Test, String)(Function(t As Test) field.GetValue(test))

        'This line indicates a compile error: 'Expression does not produce a value':
        Dim SetValue = New Action(Of Test, String)(Function(t As Test, value As String) field.SetValue(test, value))
    End Sub
 End Module


Module Module2
    Dim field = GetType(Test).GetField("Field", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance) 'Is Shared (Module)
    Sub Main2()
        Dim test = New Test
        Dim GetValue = New Func(Of Test, String)(Function(t As Test) field.GetValue(test))
        Dim SetValue = New Action(Of Test, String)(Function(t As Test, value As String) field.SetValue(test, value))
    End Sub
End Module

Не знаю, что не так, но Module2 работает просто замечательно!

Ответы [ 2 ]

5 голосов
/ 22 апреля 2009

РЕДАКТИРОВАТЬ Вычеркните мой первоначальный ответ, я неправильно понял проблему.

Причиной, по которой это не компилируется, является проблема вывода типа и позднего связывания. В первом примере поле является локальной переменной и, следовательно, может участвовать в выводе типа. Компилятор правильно выведет тип как FieldInfo. Это означает, что вызов SetValue является типизированным вызовом. Это пустой метод возврата и, следовательно, несовместимый с лямбда-выражением Function, для которого требуется возвращаемое значение.

Значение поля во втором примере объявлено на уровне модуля. Эти переменные не подлежат выводу типа и, следовательно, объект типа будет выбран. Поскольку тип является объектом, вызов SetValue становится поздним связанным вызовом. Предполагается, что все поздние связанные вызовы указывают на функцию, которая имеет тип возвращаемого значения Object. Во время выполнения, если функция возвращает void, фактически ничего не будет возвращено. Так что в этом контексте это не пустое возвращаемое выражение и, следовательно, компилируется.

Один из вариантов, который вам нужно обойти, - это явно ввести поле как Object в первом примере. Это приведет к тому, что это будет вызов с поздней привязкой, и он скомпилируется так же, как и второй

Dim field As Object = ...
1 голос
/ 22 апреля 2009

Ну вот и окончательный ответ, основанный на посте JaredPar:

Module Module1
    Sub Main()
        Dim field = GetType(Test).GetField("Field", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
        Dim test = New Test
        Dim GetValue = New Func(Of Test, String)(Function(t As Test) field.GetValue(test))
        'This line indicates a compile error: 'Expression does not produce a value': 
        Dim SetValue = New Action(Of Test, String)(Function(t As Test, value As String) DirectCast(field, Object).SetValue(test, value))
    End Sub
End Module

Обратите внимание на приведение к объекту в

Dim SetValue = New Action(Of Test, String)(Function(t As Test, value As String) DirectCast(field, Object).SetValue(test, value))
...