使用vb.net Action(Of T)和lambda声明匿名方法的问题

时间:2021-06-15 21:14:58
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!

Donno出了什么问题但是Module2工作得很好!

2 个解决方案

#1


EDIT Scratch my original answer, I misread the problem.

EDIT Scratch我的原始答案,我误解了这个问题。

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.

这不编译的原因是类型推断和后期绑定的问题。在第一个示例中,字段是局部变量,因此可以参与类型推断。编译器将正确推断出类型为FieldInfo。这意味着SetValue调用是静态类型调用。它是一个void返回方法,因此与需要返回值的Function lambda表达式不兼容。

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.

但是,第二个示例中的字段值是在模块级别声明的。这些变量不受类型推断的影响,因此将选择类型对象。由于类型是对象,因此SetValue调用成为后期绑定调用。假定所有后期绑定调用都指向返回类型为Object的函数。在运行时,如果函数返回void,则实际上将返回Nothing。所以在这种情况下,它是一个非void返回表达式,因此编译。

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

您必须解决此问题的一个选项是在第一个示例中显式地将字段键入为Object。这将强制它成为一个后期绑定调用,它将像第二个调用一样进行编译

Dim field As Object = ...

#2


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

那么这里是基于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

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))

#1


EDIT Scratch my original answer, I misread the problem.

EDIT Scratch我的原始答案,我误解了这个问题。

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.

这不编译的原因是类型推断和后期绑定的问题。在第一个示例中,字段是局部变量,因此可以参与类型推断。编译器将正确推断出类型为FieldInfo。这意味着SetValue调用是静态类型调用。它是一个void返回方法,因此与需要返回值的Function lambda表达式不兼容。

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.

但是,第二个示例中的字段值是在模块级别声明的。这些变量不受类型推断的影响,因此将选择类型对象。由于类型是对象,因此SetValue调用成为后期绑定调用。假定所有后期绑定调用都指向返回类型为Object的函数。在运行时,如果函数返回void,则实际上将返回Nothing。所以在这种情况下,它是一个非void返回表达式,因此编译。

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

您必须解决此问题的一个选项是在第一个示例中显式地将字段键入为Object。这将强制它成为一个后期绑定调用,它将像第二个调用一样进行编译

Dim field As Object = ...

#2


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

那么这里是基于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

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))