今天我在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中允许这样做?这是编译器/运行时错误吗?
答案 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
表达式解释了=运算符作为赋值而不是比较。