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

发布于 2024-10-19 20:33:05 字数 604 浏览 1 评论 0原文

那么字符串是引用类型,对吗?我的理解是,即使将字符串 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

我错过了什么?幕后到底发生了什么?我愿意用我的生命打赌,价值会改变......

So strings are reference types right? My understanding is a reference to the string in the heap is passed even when you pass the string ByVal to a method.

Sooo.....

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

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

Alternatively

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

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

What am I missing? And what is going on under the hood? I would have bet my life that the value would have changed....

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

じ违心 2024-10-26 20:33:05

引用类型在 .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 与许多对象的不同之处在于它是不可变的: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 实际上从未改变。指向它的变量只是更改为指向不同的字符串。

Reference types are passed "reference by value" in .NET. This means that assigning a different value to the actual parameter does not actually change original value (unless you use ByRef/ref). However, anything you do to change the actual object that gets passed in will change the object that the calling method refers to. For example, consider the following program:

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;
}

Output:

1
1
2

The DoSomething method assigned its a parameter to have a different value, but that parameter is just a local pointer to the location of the original a from the calling method. Changing the pointer's value did nothing to change the calling method's a value. However, DoSomethingElse actually made a change to one of the values on the referenced object.

Regardless of what the other answerers say, string is not exceptional in this way. All objects behave this way.

Where string differs from many objects is that it is immutable: there aren't any methods or properties or fields on string that you can call to actually change the string. Once a string is created in .NET, it is read-only.

When you do something like this:

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

... the compiler turns this into something like this:

// 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();

This last line generates a new string, but S1 and S2 are still hanging around. If they are constant strings built into the assembly, they'll stay there. If they were created dynamically and have no more references to them, the garbage collector can de-reference them to free up memory. But the key is to realize that S1 never actually changed. The variable pointing to it just changed to point to a different string.

望喜 2024-10-26 20:33:05

除非您另外指定,否则一切都按值传递。当您传递字符串时,实际上是按值传递引用。

对于字符串来说,这没有太大区别,因为字符串是不可变的。这意味着您永远无法修改收到的字符串。不过,对于其他类,您可以修改按值传递的对象(除非它像 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 中,当您通过引用传递时,它并不总是很清楚,当某些方法开始意外地破坏您的变量时,可能会导致很多问题。

Everything is passed by value unless you specify otherwise. When you're passing a String, you're actually passing a reference by value.

For Strings, this doesn't make much difference, as Strings are immutable. Meaning you never get to modify the string you receive. For other classes, though, you can modify an object passed by value (unless, like String, it is immutable). What you can't do, and what passing by reference allows you to do, is modify the variable you're passing.

Example:

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

Now, this should be used very sparingly, because by-value is the default and expected. Particularly in VB, which doesn't always make it clear when you're passing by reference, it can cause a lot of problems when some method starts unexpectedly mucking around with your variables.

眼眸 2024-10-26 20:33:05

默认情况下,包括引用类型在内的所有类型均按值传递,如您的示例所示,这意味着传递引用的副本。因此,无论如何,当您按值传递对象时,重新分配这样的对象将不会产生任何效果。您只是更改引用的副本所指向的内容。您必须显式地通过引用传递才能实现您想要做的事情。

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

All types, including reference types are passed by value by default, as in your example, which means that a copy of the reference is passed. So, so no matter what, re-assigning an object like that would have no effect when you pass it by value. You're just changing what the copy of the reference points to. You must explicitly pass by reference to achieve what you're trying to do.

It's only when you modify an object that's passed by value can the effect be seen outside of the method. Of course strings are immutable, so this doesn't really apply here.

我偏爱纯白色 2024-10-26 20:33:05

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

阅读 Microsoft 的这篇文章

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

You are passing a copy not the actual reference.

read this article from microsoft

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

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

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

  1. When you pass the string to the method, a copy of the reference is taken. Thus, Value is a whole new variable that just happens to still refer to the same string in memory.
  2. The "test" string literal is also created as a real reference type object. It's not just a value in your source code.
  3. When you assign "test" to Value, the reference for your Value variable is updated to refer to "test" instead of the original string. Since this reference is just a copy (as we saw in step 1), the myTestValue variable outside of the function remains unchanged and still refers to the original string.

You can get a better understanding of this by testing on a type with a property you can update. If you make a change to just the property, that change is visible outside the function. If you try to replace the entire object (as you are doing with this string), that is not visible outside the function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文