为了回答您的问题,我们先来看看 ValueTypes
ValueType 保存值。也就是说,它并不指向另一个保存该值的内存位置,而是它的内存位置就是该值。
所以
int i = 10;
int j = i;
这里发生的情况是将 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; }
}