繁体   English   中英

在VB.NET和C#中传递字符串ByVal

[英]Passing string ByVal in VB.NET AND C#

所以字符串是引用类型对吗? 我的理解是,即使将字符串ByVal传递给方法,也会传递对堆中字符串的引用。

SOOO .....

String myTestValue = "NotModified";
TestMethod(myTestValue);
System.Diagnostics.Debug.Write(myTestValue); /* myTestValue = "NotModified" WTF? */

private void TestMethod(String Value)
{
    Value = "test1";
}

另外

Dim myTestValue As String = "NotModified"
TestMethod(myTestValue)
Debug.Print(myTestValue) /* myTestValue = "NotModified" WTF? */

Private Sub TestMethod(ByVal Value As String)
    Value = "test1"
End Sub

我错过了什么? 引擎盖下发生了什么? 我会打赌我的生活价值会发生变化......

引用类型在.NET中传递“按值引用”。 这意味着为实际参数指定不同的值实际上不会更改原始值(除非您使用ByRef / ref)。 但是,您更改传入的实际对象所做的任何操作都将更改调用方法引用的对象。 例如,请考虑以下程序:

void Main()
{
    var a = new A{I=1};
    Console.WriteLine(a.I);
    DoSomething(a);
    Console.WriteLine(a.I);
    DoSomethingElse(a);
    Console.WriteLine(a.I);
}

public void DoSomething(A a)
{
    a = new A{I=2};
}

public void DoSomethingElse(A a)
{
    a.I = 2;
}

public class A
{
    public int I;
}

输出:

1
1
2

DoSomething方法将它的a参数具有不同的值,但该参数仅仅是一个局部指针到原来的位置, a从调用方法。 改变指针的值没有做任何改变调用方法的a值。 但是, DoSomethingElse实际上对引用对象上的某个值进行了更改。

无论其他回答者说什么, string都不是这样的例外。 所有对象都以这种方式运行。

string与许多对象的不同之处在于它是不可变的:字符串上没有任何方法或属性或字段可以调用以实际更改字符串。 一旦在.NET中创建了一个字符串,它就是只读的。

当你做这样的事情:

var s = "hello";
s += " world";

...编译器把它变成这样的东西:

// this is compiled into the assembly, and doesn't need to be set at runtime.
const string S1 = "hello"; 
const string S2 = " world"; // likewise
string s = S1;
s = new StringBuilder().Append(s).Append(S2).ToString();

最后一行生成一个新字符串,但S1和S2仍然悬空。 如果它们是装配中内置的恒定字符串,它们将保留在那里。 如果它们是动态创建的并且没有对它们的更多引用,则垃圾收集器可以取消引用它们以释放内存。 但关键是要意识到S1从未真正改变过。 指向它的变量只是改为指向不同的字符串。

除非另有说明,否则所有内容都按值传递。 当您传递String时,实际上是按值传递引用。

对于字符串来说,这并没有多大区别,因为字符串是不可变的。 这意味着你永远无法修改你收到的字符串。 但是,对于其他类,您可以修改按值传递的对象(除非像String一样,它是不可变的)。 你不能做的,以及通过引用传递的内容允许你做的是修改你传递的变量

例:

Public Class Example
    Private Shared Sub ExampleByValue(ByVal arg as String)
        arg = "ByVal args can be modifiable, but can't be replaced."
    End Sub

    Private Shared Sub ExampleByRef(ByRef arg as String)
        arg = "ByRef args can be set to a whole other object, if you want."
    End Sub

    Public Shared Sub Main()
        Dim s as String = ""
        ExampleByValue(s)
        Console.WriteLine(s)  ''// This will print an empty line
        ExampleByRef(s)
        Console.WriteLine(s)  ''// This will print our lesson for today
    End Sub
End Class

现在,应该非常谨慎地使用它,因为按值是默认值和预期值。 特别是在VB中,当你通过引用传递时并不总是很清楚,当某些方法开始意外地使用你的变量时,它会引起很多问题。

默认情况下,所有类型(包括引用类型)都按值传递,如示例所示,这意味着传递引用的副本 所以,无论如何,重新分配这样的对象,当你按值传递时,它将没有任何效果。 您只需更改参考副本指向的内容即可。 您必须通过引用明确传递以实现您要执行的操作。

只有当你修改一个按值传递的对象时,才能在方法之外看到效果。 当然字符串是不可变的,所以这并不适用于此。

您传递的副本不是实际参考。

从微软阅读这篇文章

http://msdn.microsoft.com/en-us/library/s6938f28.aspx

  1. 将字符串传递给方法时, 获取引用的副本 因此, Value是一个全新的变量,恰好仍然引用内存中的相同字符串。
  2. "test"字符串文字也被创建为实际引用类型对象。 它不仅仅是源代码中的值。
  3. "test"分配给ValueValue变量的引用会更新为引用"test"而不是原始字符串。 由于此引用只是一个副本(正如我们在步骤1中看到的),函数外部的myTestValue变量保持不变,仍然引用原始字符串。

通过测试具有可更新属性的类型,可以更好地理解这一点。 如果仅对属性进行更改,则该更改在函数外部可见。 如果您尝试替换整个对象(就像使用此字符串一样),则在函数外部不可见。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM