views:

1772

answers:

2
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

Donno what's wrong but Module2 works just great!

+5  A: 

EDIT Scratch my original answer, I misread the problem.

The reason this does not compile is an issue of type inference and late binding. In the first example field is a local variable and hence can participate in type inference. The compiler will correctly deduce the type to be FieldInfo. This means the SetValue call is a statically typed call. It is a void returning method and is hence incompatible with a Function lambda expression which requires a return value.

The field value in the second example though is declared at a module level. These variables are not subject to type inference and hence the type object will be chosen. Since the type is object, the SetValue call becomes a late bound call. All late bound calls are assumed to point to a function that has a return type of Object. At runtime if the function returns void, Nothing will actually be returned. So in this context it is a non-void returning expression and hence compiles.

One option you have to work around this is to explicitly type field as Object in the first example. This will force it to be a late bound call and it will compile just like the second one

Dim field As Object = ...
JaredPar
why does the second one work fine?
Nathan W
donno, it doestry and see
Shimmy
@Nathan, I misread the problem and updated my answer.
JaredPar
That sounds a bit better +1
Nathan W
I prefer to cast it, because I need it in more cases where I use it directly.look at the post.
Shimmy
while enjoying from intellisense support around.
Shimmy
+1  A: 

Well here is the final answer based on JaredPar's post:

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

Notice the cast to object at

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