本文介绍了.NET:引用传递是谎言吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个有趣的情况,在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代码。如果执行此操作时感到疼痛,请停止操作

这一切都是有道理的,但你必须理解其中的逻辑。跟随

  • 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对引用传递的值的处理方式不同并不是偶然的!

C#的设计原则包括,编译器应该在代码看起来错误的时候告诉你,特别是编译器不应该通过猜测你的意思来"掩盖"问题,并发出代码让它在大部分时间里都能工作。设计团队认为C#程序员的态度是"编译器是我的朋友,当我犯错时,他会告诉我,这样我就可以改进"。

VB的设计原则包括代码可能工作得很好,如果有看起来不太正确的地方,找出用户的意思并使其工作,即使这意味着引入不保留对象标识的代码,或者添加隐藏的复制入复制出或其他任何东西。设计团队认为VB程序员的态度是"编译器经常挡住我的路;我已经表达了一个意图,所以让它发挥作用"。

这两个设计原则都是完全合理的,每个原则都有大量的开发人员支持。我认为微软花了几十年的时间将语言开发的费用翻了一番,这样开发人员就有能力选择一种适合他们性格的语言,这是相当好的。

也就是说:在C#中,编译器会执行类似的操作:创建一个临时变量,为其赋值,然后通过引用传递该变量。

挑战:创建一个证明这一事实的程序。

提示1:可变结构在C#中是一种糟糕的做法,这是有原因的。

提示2:在C#中,变量在什么情况下被视为值?

这篇关于.NET:引用传递是谎言吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 11:29