简体   繁体   English

通过引用传递引用vs通过值传递引用-C#

[英]Pass reference by reference vs pass reference by value - C#

Greetings, 问候,

I get the difference between pass by value and pass by reference. 我得到按值传递和按引用传递之间的区别。 But pass reference (such as array) by ref and pass array by value is something i can't seem to comprehend. 但是我似乎无法理解通过ref传递引用(例如array)和通过value传递数组。 How can you pass a reference by reference? 如何通过参考传递参考?

     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

If you pass a reference by reference you can make the variable passed in point to a new object. 如果逐个引用地传递引用,则可以使变量直接指向新对象。 If you pass the reference by value you still can change the state of the object, but you can't make the variable point to a different object. 如果按值传递引用,您仍然可以更改对象的状态,但不能使变量指向其他对象。

Example: 例:

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
}

In order to answer your question let's first look at ValueTypes A ValueType holds the Value. 为了回答您的问题,让我们首先看一下ValueTypes。ValueType包含Value。 That is it does not in turn point to another memory location that holds the value but rather it's memory location is the value. 就是说,它并不指向另一个保存该值的存储位置,而是它的存储位置就是该值。

so int i = 10; 所以int = 10;

int j = i; int j = i;

What happens here is that a copy of the value of i is assigned to j. 这里发生的是将i的值的副本分配给j。 They both have the same value but they are different locations in memory. 它们都具有相同的值,但是它们在内存中的位置不同。 In oter words, each time you assign a valuetype to another valuetype, a copy is made. 换句话说,每次将一个值类型分配给另一个值类型时,都会创建一个副本。

Contract this with ReferenceTypes. 与ReferenceTypes签订合同。

object o = 10; o = 10;

object p = o; 对象p = o;

because o is a ReferenceType o points to a memory location that holds the value of 10 (it is really boxed but I'll keep it simple). 因为o是ReferenceType,所以o指向保存值为10的内存位置(它实际上是装箱的,但我将使其保持简单)。 In the next line p now points to the same memory location. 现在,在下一行中,p指向相同的存储位置。 In other words, reference tyes have two things going. 换句话说,参考轮胎有两件事。 1. An address pointer 2. The actual memory location (that address points to) that holds the actual "thing". 1.地址指针。2.该地址指向的实际存储器位置,用于保存实际的“事物”。

If you get it do far, then we can move on the passing by value and by reference. 如果您能做到这一点,那么我们可以继续按值和按引用进行传递。

In C# parameters are passed by value. 在C#中,参数按值传递。 So if you're passing a valueType to a method that expects a valuetype parameter, then 因此,如果将valueType传递给需要valuetype参数的方法,则

int i = 10;
SomeMethod(i);
Console.WriteLine(i);

static void SomeMethod(int value)
{
  value = 20;
}

When the call is made to SomeMethod a copy of the value of i is sent to the method. 当调用SomeMethod时,会将i值的副本发送到该方法。 If the method manipulates the parameter, it does not affect the original variable i. 如果该方法操纵参数,则不会影响原始变量i。 So what you'll see in the console window is 10; 因此,您将在控制台窗口中看到10。

contract this with reference types; 与参考类型签约;

  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; }
  }

Since c is a reference type. 由于c是引用类型。 And C# passes parameters by value. C#通过值传递参数。 a copy of the "value" of the reference is passed. 传递引用的“值”的副本。 That is the value of the Address c is pointing to is passed. 那就是地址c指向的值被传递。 In the method, since the address is the same (it's a copy but it points to the same memory location), the method is able to manipulate the state of object. 在该方法中,由于地址相同(它是一个副本但指向相同的内存位置),因此该方法能够操纵对象的状态。 So what you'll see in the console window is "John" and not "Mike". 因此,您将在控制台窗口中看到的是“ John”而不是“ Mike”。

However, if the method attempts to assign another instance to the parameter (called "customer" in this case). 但是,如果该方法尝试将另一个实例分配给该参数(在这种情况下称为“客户”)。 then things change. 然后事情变了。

  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; }
  }

Notice that in the method we create a new instance of a Customer and assign it to the parameter customer and we set the name of this new instance to "John". 注意,在该方法中,我们创建了一个Customer的新实例,并将其分配给参数customer,并将此新实例的名称设置为“ John”。 What we'll see in the console window is "Mike" and not john. 我们将在控制台窗口中看到的是“麦克”,而不是约翰。

That is because a copy of the original variable (c) was made before passing it to the method. 这是因为在将原始变量(c)传递给该方法之前已对其进行了复制。 While now in the method we have another address and then manipulate that new address so the original instance is untouched. 现在在该方法中,我们有另一个地址,然后操纵该新地址,以使原始实例保持不变。 Make sense? 说得通?

Ok, if that makes sense. 好吧,如果有道理。 then what if we actually wanted the SomeMethod to be able to do what we attempted to do? 那么,如果我们实际上希望SomeMethod能够完成我们尝试做的事情呢? Well, then the parameter can't be passed by value but it has to be passed by reference. 好吧,那么该参数不能按值传递,而必须按引用传递。 Meaning that the variable c and the two part (the value of address it is pointing and the address itself) are being passed. 意味着正在传递变量c和两个部分(它指向的地址值和地址本身)。 So now you're passing a reference type by reference. 因此,现在您通过引用传递引用类型。

  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; }
  }

I suggest that you check out this link . 我建议您检查一下此链接 It's quite useful and contains very simple examples about Parameter passing in C# . 它非常有用,并且包含有关C#中参数传递的非常简单的示例。

Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. 引用参数不会传递函数成员调用中使用的变量的值-它们本身使用变量。 Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used , so the value of the variable in the function member and the value of the reference parameter will always be the same. 不会在函数成员声明中为变量创建新的存储位置,而是使用相同的存储位置 ,因此函数成员中的变量值和引用参数的值将始终相同。 Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. 参考参数需要ref修饰符作为声明和调用的一部分-这意味着当您通过引用传递某些内容时,它始终很清晰。 Let's look at our previous examples, just changing the parameter to be a reference parameter: 让我们看一下前面的示例,只是将参数更改为参考参数:

void Foo (ref StringBuilder x) {
    x = null;
}

...

StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (ref y);
Console.WriteLine (y==null); // will write TRUE

IN YOUR EXAMPLE 在你的例子中

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 still points to the array 123    

    // now you are modifying the object pointed by THE COPY of the pointer
    // the original pointer still points to array 123
    // the copy 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

This may seem a bit confusing, but it's really not that tricky. 这似乎有些令人困惑,但实际上并不是那么棘手。 When you assign an instance of a reference type to a variable, you could say the value of that variable will be a reference to the object, not the object itself. 当您将引用类型的实例分配给变量时,可以说该变量的将是对对象的引用 ,而不是对象本身。 When you pass that variable by value to another method, you are passing a copy of the reference. 当您将该变量按值传递给另一个方法时,您正在传递引用的副本。 The called method will "see" the same instance as the calling code does. 被调用方法将“看到”与调用代码相同的实例。 If you instead pass the variable by reference, the calling method gets to see the same copy of the reference as the calling code does. 如果改为通过引用传递变量,则调用方法将获得与调用代码相同的引用副本

The difference in behavior between these to is that when you pass the variable by reference, the called method might assign another reference to the variable (make it reference another instance of the same type), and the calling code will see this change. 它们之间的行为差​​异是,当您通过引用传递变量时,被调用的方法可能会为该变量分配另一个引用(使其引用另一个相同类型的实例),并且调用代码将看到此更改。 Unless you make such assignments, there is no need to use ref . 除非您进行此类分配,否则无需使用ref

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM