提问人:iam1me 提问时间:9/6/2018 最后编辑:maccetturaiam1me 更新时间:9/6/2018 访问量:445
.NET:通过引用传递是谎言吗?
.NET: Pass-by-reference is a lie?
问:
我遇到了一个有趣的案例,其中引用传递似乎在 VB.NET 中不起作用。我在下面提供了一些示例代码供大家使用。谁能解释这种现象。这是故意的,还是语言/编译器的错误?
我在此代码中看到的是“增量后”读数与“增量前”读数相同。
Public Class Wrapper
Public Property Value As Integer
End Class
Sub Main()
Dim rand As New Random()
Dim w As New Wrapper()
w.Value = rand.Next()
Console.WriteLine("Before Increment: {0}", w.Value)
Try
Increment(w.Value)
Catch ex As Exception
End Try
Console.WriteLine("After Increment: {0}", w.Value)
Console.ReadLine()
End Sub
Public Sub Increment(ByRef i As Integer)
i += 1
Throw New Exception()
End Sub
答:
我遇到了一个有趣的案例,其中引用传递似乎在 VB.NET 中不起作用。
事实上,这是一个非常有趣的案例。
我在下面提供了一些示例代码供大家使用。谁能解释这种现象。
是的。
这是故意的,还是语言/编译器的错误?
此行为是设计使然,不是错误。你不应该像这样编写 VB 代码。如果这样做时很痛,请停止这样做。
这一切都是有道理的,但你必须理解它的逻辑。遂
- byref 是变量的别名。也就是说,当您将变量传递给采用 byref 的方法时,形式参数将成为该变量的别名。我们有一个变量,有两个名称。
- 属性不是变量。属性是一对方法:getter 和 setter。属性可以由变量支持,但属性不是变量。它是产生值的 getter 和接收值的 setter。确保您清楚值和变量之间的区别。变量包含值。
- 然后,如果尝试将属性传递给需要 byref 参数的方法,会发生什么情况?在 C# 中,这是非法的。在 VB 中,编译器会为您生成一个临时变量,并使用 copy-in-copy-out 语义通过 ref 传递该变量。也就是说,您的程序等同于:
Try
Dim Temp As Integer
Temp = w.Value ' copy-in
Increment(Temp) ' make an alias to Temp
w.Value = Temp ' copy-out
Catch ex As Exception
End Try
现在应该很明显为什么你的程序有这样的行为。抛出发生在复制之前。
人们常说 C# 和 VB 是“同一种语言”,但语法不同,这有一定的道理。但是,显示微小差异的示例说明了这些语言具有不同的设计原则。C# 和 VB 在处理 ref 传递的值方面有所不同,这并非偶然!
C# 的设计原则包括编译器应该在代码看起来错误时告诉你,特别是编译器不应该通过猜测你的意思来“掩盖”问题,并发出代码让它在大多数时候都能工作。设计团队认为 C# 程序员的态度是“编译器是我的朋友,当我出错时告诉我,这样我就可以改进”。
VB 的设计原则包括代码可能工作得很好,如果有什么东西看起来不太对劲,弄清楚用户的意思并让它工作,即使这意味着引入不保留对象身份的代码,或者添加隐藏的复制进复制或其他什么。设计团队认为 VB 程序员的态度是“编译器经常挡住我的路;我已经表达了一个意图,所以让它发挥作用”。
这两种设计原则都是完全明智的,并且每个原则都有大量的开发人员选区。我认为Microsoft花了几十年的时间将语言开发的费用翻了一番,以便开发人员能够选择适合他们气质的语言,这真是太好了。
也就是说:在 C# 中,编译器会执行类似的操作:创建一个临时变量,为其赋值,然后通过 ref 传递变量。
挑战:创建一个程序来证明这一事实。
提示 #1:可变结构在 C# 中是一种不好的做法,这是有原因的。
提示 #2:在什么情况下,变量在 C# 中被视为值?
评论
w.Value = Temp
也许应该被删除?根据您的描述,这意味着我认为这不代表 OP 的代码,因为正在更新而没有更新。Temp
w.Value
for(...n times...) { int b = blah(); }
int b1 = blah(); int b2 = blah(); int b3 = blah(); ... int bn = blah();
评论