VB.NET函数返回

32
为了从 VB.NET 函数中返回一个值,可以将一个值赋给函数名或使用 "return value"。
我有时会在同一个函数中混用这两种方法。个人而言,我更喜欢使用 return。
我的问题是,这两者之间有什么内部区别(如果有的话)?
8个回答

57

区别在于它们执行不同的任务!

“返回值”有两个作用:
1. 设置函数在该点的返回值 2. 立即退出函数

函数中没有其他代码会执行!

“函数名 = 值”只有一个作用:
1. 在该点设置函数返回值

函数中的其他代码将继续执行,这使得可以使用其他逻辑来优化或覆盖函数的返回值。

这是很大的区别。请记住,这不仅与状态有关,也与流程有关。


1
他没有询问那个。他询问的是如何使用返回值(而不是语句)或将该值分配给函数名称。 - StingyJack
4
他实际上问的是:“我的问题是,这两者之间是否存在内在的差异?” - Wagner Leonardi
@StingyJack - 你理解这个问题是关于“使用返回值(而不是语句)”。我不确定这是什么意思,但我确信这里的共识是问题中的“返回值”确实指的是返回语句,“值”指的是它的参数。在你给我的另一个评论中,你引用了https://dev59.com/K3RB5IYBdhLWcg3w9b99#451149,其中清楚地比较了将FunctionName分配给使用返回语句的情况,使用了一个微不足道的例子。如上所述,对于任何非微不足道的示例,IL都将有所不同。 - Michael Krebs

20

让我们来看一下...奇怪的是"functionName ="生成更少的IL代码?

代码:

Public Function Test() As String
    Test = "Test"
End Function


Public Function Test2() As String
    Return "Test"
End Function

IL:

.method public static string Test() cil managed
{
    .maxstack 1
    .locals init (
        [0] string Test)
    L_0000: nop 
    L_0001: ldstr "Test"
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ret 
}

.method public static string Test2() cil managed
{
    .maxstack 1
    .locals init (
        [0] string Test2)
    L_0000: nop 
    L_0001: ldstr "Test"
    L_0006: stloc.0 
    L_0007: br.s L_0009
    L_0009: ldloc.0 
    L_000a: ret 
}

1
有趣的是:隐式返回节省了一条指令。 - Joel Coehoorn
不错的帖子。为什么需要跳转到L_0009分支?也许只是因为返回没有被优化掉吗? - user50612
3
“Return is compatible with C#”这种写法更易于许多程序员理解,而且听起来更加自然流畅。 - Rulas
Rulas,你的评论与正题无关且没有理由,评论前请先阅读所有回复和评论。 - user50612
14
需要注意的是,这只是在调试模式下(因此无关紧要)!在发布模式下,生成的代码是相同的。 - Konrad Rudolph
显示剩余2条评论

17

这两者可能没有区别。据我所知,编译器生成的IL会将它们都转换为Return语句,除非还有额外使用_returnValue变量

依我之见,FunctionName赋值的可读性很差,是VB6的坏习惯之一。我更喜欢使用_returnValue(而不是RETVAL)变量的方法。


6
好的,我会尽力以通俗易懂的方式翻译,并保持原意不变。请提供需要翻译的内容。 - Jonathan.
3
@Jonathan - SO问题的答案并不总是以相同的顺序排列。你能提供帖子链接吗? - StingyJack
1
这个答案是完全错误的。IL 不会将函数名的赋值转换为返回语句,因为该赋值并不会导致函数在那个时候返回。该赋值的值仅在调用没有参数的返回语句或在“end function”处返回。 - Michael Krebs
@MichaelKrebs - 你确定吗?在发布模式下编译,即使是在简单的示例中也会显示相同的内容。请参见https://dev59.com/K3RB5IYBdhLWcg3w9b99#451149以获取另一个示例。 - StingyJack
2
@StingyJack - 是的,我确定。IL只在_trivial examples_的情况下才会相同,并且只在发布模式下。在FunctionName分配后跟随的任何函数中的代码都将被执行,而在Return调用后跟随的任何函数中的代码都不会被执行。如果还有一行以上的代码,这是一种巨大的行为差异,始终会显示为IL中的差异,在发布模式和调试模式中都是如此。这对问题“两者之间是否有任何内部差异”也非常相关。 - Michael Krebs
除非有returnValue变量的其他用途,否则不返回任何翻译。 - StingyJack

7

下面的操作仅适用于Visual Basic 6.0开发人员,以便轻松移植代码:

Public Function MyFunction() As String
    MyFunction = "Hello"
End Function

如果你的项目中包括没有使用过Visual Basic 6.0的人,我绝对不建议继续使用这种语法,因为它会让他们感到困惑。


我也在苦恼...平衡。 - Tomalak
1
我的问题是关于两者之间的内部差异,而不是偏好或最佳实践。 - user50612
虽然这样做可能会增加一些工作量,但是最好解释一下为什么你会推荐其中一种而不是另一种。 - Tomalak
这篇文章的措辞也显得过于攻击性和冒犯,尤其是使用了“你”的措辞。特别是在那种情境下,它与我的帖子相矛盾。 - user50612
已删除最后一部分,感谢指出,这就是我刚醒来时写作的结果! :) - Tom Anderson

2
当激活Tools/Options/Text Editor/All Languages/Code Lens时,参考计数将显示在每个子程序、函数或属性语句上方。
"返回值"似乎比"为函数名赋值"更好。在后一种情况下,"Code Lens"会产生一个膨胀的参考计数。
' Code Lens reports "0 references" here for Sub Rosa().
Public Sub Rosa()
    Diagnostics.Debug.WriteLine(Test())
    Diagnostics.Debug.WriteLine(Test2())
End Sub

' Code Lens reports "2 references" here for Function Test().
Public Function Test() As String
    Test = "Test"       ' Code Lens counts this as a reference.
End Function

' Code Lens reports "1 reference" here for Function Test2().
Public Function Test2() As String
    Dim strTest2 as String = "Test"
    Return strTest2     ' Code Lens does NOT count this as a reference.
End Function

1
在我看来,关于引用计数过高的问题是值得考虑的。 - phn

1

99次中有99次我会使用“返回值”。

偶尔我会有一个函数,另一种类型不仅可以让我节省变量声明,而且以一种实际上显着澄清函数的方式来完成。通常情况下,当我想要将返回值命名为与函数相同的名称时,这种情况就会发生,并且通常这些都是递归函数;这种结构的某些方面使其倾向于隐式返回变量。然而,这种情况非常罕见。我不知道在我的当前项目中是否有任何使用隐式返回变量的函数。


0

读到一个文章说返回值语法是.NET的唯一正确方式,我想“好吧,那我们就这样做吧”。然后我写了一个函数,我知道,心里清楚,无论什么情况下,它总会从Return语句中返回一个值或者抛出一个异常,但是编译器却警告说函数“并非所有路径都返回一个值”。

幸运的是,我在Stack Overflow上遇到了这个问题:如何使这个函数不产生“并非所有路径都返回值”的警告? 它解释了为什么;在函数头部添加默认值赋值给过程名称可以防止类似情况的警告。

因此,尽管我将继续使用返回值语法,只是为了保持语法的一致性,但我也会给函数名称分配一个默认值,以防止可能会使编译过程混乱的虚假警告。


0

当与第三方工厂(_hsf)合作时,这非常方便,您可以避免声明返回变量。

Public Function CreateExtremum(iShape As INFITF.Reference, iDir1 As HybridShapeTypeLib.HybridShapeDirection, iSide1 As Integer, iDir2 As HybridShapeTypeLib.HybridShapeDirection, iSide2 As Integer, iDir3 As HybridShapeTypeLib.HybridShapeDirection, iSide3 As Integer) As HybridShapeTypeLib.HybridShapeExtremum
    CreateExtremum = _hsf.AddNewExtremum(iShape, iDir1, iSide1)
    CreateExtremum.Direction2 = iDir2
    CreateExtremum.ExtremumType2 = iSide2
    CreateExtremum.Direction3 = iDir3
    CreateExtremum.ExtremumType3 = iSide3
    CreateExtremum.Compute()
End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接