簡體   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