在 ByRef 和 ByVal 之间进行选择时需要考虑哪些事项。
我了解两者之间的区别,但我不完全了解 ByRef 是否可以节省资源,或者我们是否甚至需要在 .Net 环境中担心这一点。
如果功能在某种情况下无关紧要,您如何在两者之间做出决定?
有很多关于这方面的错误信息。主要是你理解了值类型和引用类型的区别,以及按值传递和按引用传递的区别。
您几乎总是希望按值传递。通过引用传递几乎总是用于“我想返回多个结果,而不仅仅是通过将内容添加到传入的列表中”。使用传递引用的方法的经典示例是Int32.TryParse,其中返回值是成功/失败,解析值由 out 参数“返回”。
对于所有类型,默认值为 byValue,但重要的是要了解这两个选项对于“引用类型”(类)而不是值类型的含义。(结构)。
对于引用类型,如果在方法中声明引用类型变量,则该变量是方法堆栈帧中的内存位置。它不在堆上。当您初始化该变量(使用 new 或工厂等)时,您已经在堆上创建了一个实际对象,并且该对象的地址存储在方法堆栈框架中声明的引用变量中。
当您通过Val将引用类型传递给另一个方法时,您正在创建存储在调用方法堆栈中的地址的副本,并将该值的副本(指针地址)传递给被调用的方法,并将其存储在新内存中被调用的方法堆栈中的插槽。在被调用的方法内部,新克隆的变量直接指向堆上的同一个对象。所以使用它可以改变同一个对象的属性。但是您不能更改原始引用变量(在调用方法堆栈上)指向的堆对象。如果,在被调用的方法中我写
myVar = new object();
调用方法中的原始变量不会更改为指向新对象。
如果我通过引用传递一个引用类型,otoh,我传递了一个指向调用方法堆栈中声明变量的指针(其中包含指向堆上对象的指针)因此它是指向对象指针的指针。它指向调用方法堆栈上的内存位置,它指向堆上的对象。
所以现在,如果我在被调用方法中更改变量的值,通过将其设置为一个新的 object(),如上所述,因为它是对调用方法中变量的“引用”,我实际上是在更改哪个对象调用方法中的变量指向。所以被调用方法返回后,调用方法中的变量将不再指向堆上同一个原始对象。
ByVal 应该是您的“默认值”。除非您有特定理由使用 ByRef,否则请使用它
在 .net 中传递对象 ByVal 不会复制对象,也不会消耗比 ByRef 更多的资源,指针仍然传递给函数。运行时只是确保您不能修改函数中的指针并为其返回不同的值。您仍然可以更改对象内的值,并且您将在函数之外看到这些更改。这就是为什么 ByRef 很少使用的原因。仅当您想要一个函数来更改返回的实际对象时才需要它;因此是一个输出参数。
仅当参数为“输出”参数时才使用“ByRef”。否则使用“ByVal”。在明确不应返回值的参数上使用“ByRef”是危险的,并且很容易产生错误。
我认为永远不应该使用 ByRef——这是一种不好的做法。我甚至会将其应用于允许函数返回多个值(通过 ByRef 参数)的典型用例。函数返回包含这些多个返回值的结构化响应会更好。如果一个函数只通过它的 return 语句返回值,那就更清楚和更明显了。
将某些参数标记为 ByRef 向函数的用户显示分配给该参数的变量**将被修改。****
如果对所有参数都使用 ByRef,则无法判断函数修改了哪些变量,而函数只读取了哪些变量。(除了偷看函数源!)
根据 Microsoft 的说法,选择 ByVal 或 ByRef 会影响足够大的值的性能(请参阅Passing Arguments by Value and by Reference (Visual Basic)):
表现。尽管传递机制会影响代码的性能,但差异通常是微不足道的。一个例外是通过 ByVal 传递的值类型。在这种情况下,Visual Basic 复制参数的整个数据内容。因此,对于结构体这样的大值类型,通过 ByRef 传递会更有效率。
[强调补充]。
Sub last_column_process()
Dim last_column As Integer
last_column = 234
MsgBox last_column
trying_byref x:=last_column
MsgBox last_column
trying_byval v:=last_column
MsgBox last_column
End Sub
Sub trying_byref(ByRef x)
x = 345
End Sub
Sub trying_byval(ByRef v)
v = 555
End Sub
很多困惑我会尽量简化。你基本上有4个选择:
有人说你永远不应该使用 byRef。虽然它们在技术上是正确的,但有一件事是肯定的。你不应该使用从不这个词。如果您是从头开始设计系统,那么应该不惜一切代价避免使用 byRef。使用它会暴露一个设计缺陷。然而,在现有系统上工作可能无法提供足够的灵活性来实现良好的设计。有时你必须进行consessions,即使用byRef。例如,如果您可以使用 byRef 在 2 天内完成修复,那么这可能比重新发明轮子并花一周时间来获得相同的修复只是为了避免使用 byRef 更可取。
概括: