[英]Why are objects passed by value modified as if they are passed by reference?
[英]Why do c# objects once behave like passed by value and once as passed by reference?
我不了解將參數傳遞給C#中的方法的一件事。 從我看到的情況來看,c#中的對象有時的行為就像是通過引用傳遞的,一次就像是通過值傳遞的。 在這段代碼中,我按引用傳遞給method()
,按值傳遞一次。 這兩個都按預期執行。 但是當我創建Update()
並按值傳遞對象時,我看到它的行為就像是在更新原始對象。
為什么我用Update(myString input)
更新原始對象,卻不使用method(myString input)
更新它?
這是不合邏輯的!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ClassPassing
{
class Program
{
static void Main(string[] args)
{
myString zmienna = new myString();
Update(zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
zmienna.stringValue = "This has run in main";
zmienna.stringValue2 = "This is a help string";
method(zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
method(ref zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
}
static void method(myString input)
{
input = new myString();
}
static void method(ref myString input)
{
input = new myString();
}
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
}
public class myString
{
public string stringValue { get; set; }
public string stringValue2 { get; set; }
public myString() { stringValue = "This has been just constructed"; this.stringValue2 = "This has been just constructed"; }
}
}`
您必須了解您的代碼:
static void method(myString input)
{
input = new myString();
}
在這里,您按值傳遞對對象的引用
static void method(ref myString input)
{
input = new myString();
}
在這里,您將引用逐個引用傳遞
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
在這里,您再次按值傳遞對對象的引用
現在:
僅在簡單(int,float等)類型和struct
s情況下,才在C#中按值進行實際傳遞:
class Program
{
public struct MyStruct
{
public int i;
}
public class MyClass
{
public int i;
}
public static void Modify(MyStruct s)
{
s.i = 99;
}
public static void Modify(MyClass c)
{
c.i = 99;
}
public static void Main(string[] args)
{
MyStruct myStruct = new MyStruct();
myStruct.i = 20;
MyClass myClass = new MyClass();
myClass.i = 20;
Modify(myStruct);
Modify(myClass);
Console.WriteLine("MyStruct.i = {0}", myStruct.i);
Console.WriteLine("MyClass.i = {0}", myClass.i);
Console.ReadKey();
}
}
結果:
MyStruct.i = 20
MyClass.i = 99
在這種情況下, MyStruct
的值保持不變,因為它是通過value傳遞給函數的 。 另一方面, MyClass
的實例通過引用傳遞,這就是其值更改的原因。
根本不傳遞對象 。
對於引用類型的表達式(類,接口等) 引用傳遞-通過值默認,但如果你使用的變量的引用傳遞ref
。
重要的是要了解zmienna
的值不是對象,而是參考。 排序后,其余的變得簡單。 這不僅用於傳遞參數,還用於所有參數 。 例如:
StringBuilder x = new StringBuilder();
StringBuilder y = x;
y.Append("Foo");
Console.WriteLine(x); // Prints Foo
這里的x
和y
值是對同一個對象的引用-就像有兩張紙,每張紙上都有相同的街道地址。 因此,如果某人通過閱讀x
寫的地址來訪問房屋並將前門塗成紅色,那么其他人通過閱讀y
寫的地址來訪問同一所房屋,第二個人也將看到一個紅色的前門。
這里可能有多個問題要回答,但是關於您的最后一個問題:
"Why do I update original object with Update(myString input) but do not update it with method(myString input)?"
在這里,您正在創建myString
類的新實例,而不引用作為參數傳遞給該方法的原始實例。 因此,如果您在方法內部更改input.stringValue2
的值,則input.stringValue2
該方法后,該值將丟失。
static void method(myString input)
{
input = new myString();
}
但是在這里,您引用的是傳遞給它的原始實例。 當您離開此方法時,原始myString
實例將保留stringValue2
的值。
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
將計算機內存想象成一組盒子,您可以使用標簽為它們命名。
myString zmienna = new myString();
在這里,您分配了一個包含myString
實例的框,並帶有標簽zmienna
指向它。 然后:
static void method(myString input)
{
input = new myString();
}
在此方法中, input
是另一個標簽。 調用該方法時,首先將標簽input
指向帶有初始實例的同一框。 但是,在方法的主體中,您分配了另一個框,然后將標簽 input
更改為指向該新框。 第一個框什么也沒做,而zmienna
標簽什么也沒做。
static void method(ref myString input)
{
input = new myString();
}
在這里,由於使用了ref
關鍵字,您不僅要傳遞第一個“內存盒”的下落,而且要給出實際的標簽。 因此,此方法的主體將更新標簽zmienna
使其指向具有myString
的第二個實例的新創建的框。 第一個框被遺忘,因為沒有標簽指向它。
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
在這種情況下,您以與第一種方法完全相同的方式傳遞第一個框的地址。 因此,您有兩個標記: zmienna
和input
-都指向同一個框。 因此, input.stringValue2
在zmienna
指向的同一框中訪問字段stringValue2
。
實際使用的精確術語是參考,而不是我在此說明中使用的標簽術語。 我以某種方式發現許多人發現以這種方式更容易理解:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.