动作在VB.NET中表现得像Func

时间:2011-09-22 13:11:42

标签: vb.net compiler-construction

今天我在VB.NET中目睹了一些非常奇怪的行为。我正在谈论的代码如下:

Option Strict On
Option Explicit On

Module Module1

    Sub Main()
        Dim thisShouldBeSet = False

        DoSomething(Function() thisShouldBeSet = True)

        If Not thisShouldBeSet Then
            Throw New Exception()
        End If

        Console.WriteLine("yaay")
    End Sub

    Sub DoSomething(action As Action)
        action.Invoke()
    End Sub
End Module

我知道代码本身存在缺陷,因为我必须使用:

DoSomething(Sub() thisShouldBeSet = True)

而不是:

DoSomething(Function() thisShouldBeSet = True)

但我觉得很奇怪,即使使用Option Strict和Option Explicit,编译也允许我编译这段代码。

更奇怪的是,在运行代码时,Action实际上表现得像一个Func(布尔值)。

任何人都可以向我提供有效解释为什么在VB.NET中允许这样做?这是编译器/运行时错误吗?

2 个答案:

答案 0 :(得分:8)

为什么不允许你编译代码? thisShouldBeSet = True是有效的比较,返回值False(因为thisShouldBeSet <> True)。请记住,VB中的=可能意味着C#中的=(赋值)和==(比较),具体取决于上下文。

详细说明,Sub() thisShouldBeSet = True将是

的简写
Sub Anonymous()
    thisShouldBeSet = True           ' Assignment
End Sub

Function() thisShouldBeSet = True

的简写
Function Anonymous() As Boolean
    Return thisShouldBeSet = True    ' Comparison
End Sub

在VB中,明确允许使用具有返回值的函数作为Action。从System.Action delegate的文档(由我突出显示):

  

在C#中,该方法必须返回void。在Visual Basic中,它必须由Sub ... End Sub构造定义。 它也可以是返回忽略值的方法。

答案 1 :(得分:1)

这里发生的是你正在创建一个closure

你的lamdba方法在两种情况下都表现得像一个函数而不是一个sub,因为你已经从Main方法中捕获/关闭了thisShouldBeSet变量,并且Sub的thisShouldBeSet = True表达式解释了=运算符作为赋值而不是比较。