首页 > 解决方案 > vb.net通过函数传递列表而不更改列表值

问题描述

此处的列表值在传递 ByVal 时发生了变化,为什么不能更改。

Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
        Dim value As Integer = 1
        Dim value2 As New List(Of Decimal)
        value2.Add(1)
        value2.Add(2)

        ' The integer value doesn't change here when passed ByVal.
        Example1(value)
        Console.WriteLine(value)

        ' The list value changeed here when passed ByVal.
        Example3(value2)
        Console.WriteLine(value)

结束子

    Sub Example1(ByVal test As Integer)
        test = 10
    End Sub

    Sub Example3(ByVal test As List(Of Decimal))
        test.Add(3)
    End Sub

它解决了,解决方案是制作新副本:

Sub Example3(ByVal test As List(Of Decimal))
        Dim testnew As New List(Of Decimal)
        testnew.AddRange(test)
        testnew.Add(3)
    End Sub

标签: vb.netlistfunctionarguments

解决方案


您需要阅读值类型和引用类型以及按值和按引用传递方法参数。它们是相关的,但不是一回事。当您按值传递方法参数时,您会创建正在传递的变量的副本。如果变量是值类型,即结构,那么这意味着创建值的副本。如果变量是引用类型,即类,那么这意味着创建引用的副本。问题是,原始引用和副本仍然引用同一个对象。

存在引用类型的原因是您不希望每次将大型对象分配到某个位置时都创建它们的副本。在将集合传递给方法的情况下,几乎总是这样,您在方法内部所做的任何更改都希望在外部反映出来。在极少数情况下,您可以先创建集合的副本并将其传入。

当您按值传递值类型时,您会创建该值的副本。这意味着您在方法内部所做的任何更改都不会影响原始变量。您可以为参数分配一个新值,也可以设置该值的属性,并且更改不会反映在方法之外。当然,值类型通常应该是不可变的,因此设置属性应该是不可能的,但有时该“规则”会被打破。

当您按值传递引用类型时,您会创建引用的副本。这意味着为方法内部的参数分配不同的对象不会影响原始变量。但是仍然只有一个对象,由原始变量和参数引用。因此,如果您通过参数设置该对象的属性,那么该更改将反映在原始变量中,因为它是同一个对象。

通过引用传递值类型时,会创建对该值的新引用。这意味着您在方法内所做的任何更改都会影响原始变量。您可以为参数分配一个新值,也可以设置该值的属性,并且更改将反映在方法之外。

当您通过引用传递引用类型时,您将创建对原始引用的新引用。这意味着将不同的对象分配给方法内部的参数将影响原始变量。仍然只有一个对象,因此在参数上设置属性仍然会影响原始变量。

这些是仅有的四种可能性:按值的值类型、按值的引用类型、按引用的值类型和按引用的引用类型。在这些场景中,都不是引用类型对象的副本,因此在这些场景中,您都不能通过方法参数设置引用类型对象的属性,并且该更改不会反映在原始变量中。

如果您想要原始对象的副本,则由您明确创建一个。是在方法内部还是外部这样做,实际上取决于具体情况。这意味着您需要将代码更改为:

Sub Example3(ByVal test As List(Of Decimal))
    Dim copy = test.ToList()

    copy.Add(3)
End Sub

或这个:

Dim copy = value2.ToList()

Example3(copy)

让我在这里重复重点:没有办法将引用类型对象传递给方法,通过方法内部的参数修改对象并且不影响原始变量(为参数分配不同的对象不是修改对象)。如果您希望在方法内部进行修改以不影响原始变量,那么您需要对象的副本,并且唯一发生的方法是您明确地执行此操作。


推荐阅读