为了回答你的问题,让我们首先看一下 ValueTypes ValueType 持有价值。也就是说,它并不反过来指向另一个保存该值的内存位置,而是它的内存位置就是该值。
所以 int i = 10;
诠释 j = 我;
这里发生的情况是将 i 的值的副本分配给 j。它们都具有相同的值,但它们在内存中的位置不同。换句话说,每次你将一个值类型分配给另一个值类型时,都会创建一个副本。
与 ReferenceTypes 签约。
对象o = 10;
对象 p = o;
因为 o 是一个 ReferenceType o 指向一个保存值为 10 的内存位置(它确实是装箱的,但我会保持简单)。在下一行中,p 现在指向相同的内存位置。换句话说,引用类型有两件事要做。1. 地址指针 2. 保存实际“事物”的实际内存位置(该地址指向)。
如果你能做到这一点,那么我们可以继续通过值和引用传递。
在 C# 中,参数是按值传递的。因此,如果您将 valueType 传递给需要 valuetype 参数的方法,那么
int i = 10;
SomeMethod(i);
Console.WriteLine(i);
static void SomeMethod(int value)
{
value = 20;
}
当调用 SomeMethod 时,会将 i 值的副本发送到该方法。如果方法操作参数,它不会影响原始变量 i。因此,您将在控制台窗口中看到 10;
将此与引用类型签约;
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(c);
Console.WriteLine(c.Name);
}
static void SomeMethod(Customer customer)
{
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
因为 c 是引用类型。而 C# 按值传递参数。传递了引用的“值”的副本。即传递了 c 指向的地址的值。在该方法中,由于地址是相同的(它是一个副本,但它指向相同的内存位置),该方法能够操作对象的状态。因此,您将在控制台窗口中看到的是“John”而不是“Mike”。
但是,如果该方法尝试将另一个实例分配给参数(在这种情况下称为“客户”)。然后事情发生了变化。
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(c);
Console.WriteLine(c.Name);
}
static void SomeMethod(Customer customer)
{
customer = new Customer();
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
请注意,在该方法中,我们创建了一个 Customer 的新实例并将其分配给参数 customer,我们将这个新实例的名称设置为“John”。我们将在控制台窗口中看到的是“Mike”而不是 john。
这是因为在将原始变量 (c) 传递给方法之前已对其进行了复制。虽然现在在方法中,我们有另一个地址,然后操作该新地址,因此原始实例不受影响。有道理?
好吧,如果这有意义的话。那么如果我们真的希望 SomeMethod 能够做我们试图做的事情呢?那么,参数不能通过值传递,但必须通过引用传递。这意味着正在传递变量 c 和两部分(它指向的地址的值和地址本身)。所以现在你通过引用传递一个引用类型。
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(ref c);
Console.WriteLine(c.Name);
}
static void SomeMethod(ref Customer customer)
{
customer = new Customer();
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}