问候,
我得到传递值和传递参考之间的区别。但是通过ref传递引用(例如数组)并按值传递数组是我无法理解的。如何通过引用传递引用?
int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);
PassByVal(int[] array)
{ array = new int[] {7,8,9}; // will not work }
PassByRef(ref int[] array)
{ array = new int[] {10,11,12}; } // will work
答案 0 :(得分:7)
如果通过引用传递引用,则可以使传递的变量指向新对象。如果按值传递引用,仍然可以更改对象的状态,但不能使变量指向其他对象。
示例:强>
void RefByRef(ref object x)
{
x=new object(2);
}
void RefByValue(object x)
{
x=new object(2);//Only changes a local variable and gets discarded once the function exits
}
void Test()
{
object x1=1;
object x1a=x1;
RefByRef(ref x1);
//x1 is now a boxed 2
//x1a is still a boxed 1
object x2=1;
RefByValue(x2);
//x2 is still a boxed 1
}
答案 1 :(得分:2)
为了回答你的问题,我们先来看看ValueTypes ValueType保存Value。也就是说,它不会指向另一个保存值的内存位置,而是它的内存位置就是值。
所以 int i = 10;
int j = i;
这里发生的是i的值的副本被分配给j。它们都具有相同的值,但它们在内存中的位置不同。换句话说,每次将值类型分配给另一个值类型时,都会生成一个副本。
使用ReferenceTypes与此合约。
对象o = 10;
对象p = o;
因为o是一个ReferenceType o指向一个保存值为10的内存位置(它实际上是盒装的,但我会保持简单)。在下一行中,p现在指向相同的内存位置。换句话说,参考tyes有两件事情要做。 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”。
但是,如果方法尝试将另一个实例分配给参数(在本例中称为“customer”)。事情发生了变化。
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; }
}
答案 2 :(得分:1)
我建议您查看this link。它非常有用,包含有关Parameter passing in C#的简单示例。
引用参数不传递函数成员调用中使用的变量的值 - 它们使用变量本身。 不是在函数成员声明中为变量创建新的存储位置,而是使用相同的存储位置,因此函数成员中的变量值和引用参数的值将始终为相同。引用参数需要ref修饰符作为声明和调用的一部分 - 这意味着当你通过引用传递某些东西时它总是很清楚。让我们看一下前面的例子,只需将参数更改为参考参数:
void Foo (ref StringBuilder x) {
x = null;
}
...
StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (ref y);
Console.WriteLine (y==null); // will write TRUE
在您的示例中
int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);
PassByVal(int[] array){
// the function copy the value of the pointer in a new location of memory
// the "copied" pointer stil poin to the array 123
// now you are modifying the object pointed by THE COPY of the pointer
// the original pointer stil point to array 123
// the copoy of the pointer will point to array 456
array = new int[] {7,8,9};
} // will not work
PassByRef(ref int[] array){
// here you are passing the pointer without creating a copy of it in a
// new location of memory
// we have not a original pointer and a "copyed" pointer
// we have only the original pointer and now whe point it to array 10,11,12
array = new int[] {10,11,12};
} // will work
答案 3 :(得分:0)
这看起来有点混乱,但实际上并不是那么棘手。将引用类型的实例分配给变量时,可以说该变量的值将引用到对象,而不是对象本身。当您将该变量按值传递给另一个方法时,您将传递该引用的副本。被调用的方法将“看到”与调用代码相同的实例。如果您通过引用传递变量,则调用方法可以像调用代码一样查看引用的相同副本。
这些之间的行为差异在于,当您通过引用传递变量时,被调用的方法可能会为变量分配另一个引用(使其引用另一个相同类型的实例),并且调用代码将看到此更改。除非您进行此类分配,否则无需使用ref
。