Pass reference by reference vs pass reference by value - C#

好久不见. 提交于 2021-02-06 13:58:38

问题


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. 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

回答1:


I suggest that you check out this link. It's quite useful and contains very simple examples about Parameter passing in 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. 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



回答2:


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
}



回答3:


In order to answer your question let's first look at ValueTypes A ValueType holds the 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 j = i;

What happens here is that a copy of the value of i is assigned to 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.

object o = 10;

object 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). In the next line p now points to the same memory location. 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".

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. So if you're passing a valueType to a method that expects a valuetype parameter, then

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. If the method manipulates the parameter, it does not affect the original variable i. So what you'll see in the console window is 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. And C# passes parameters by value. a copy of the "value" of the reference is passed. That is the value of the Address c is pointing to is passed. 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".

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". 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. 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? 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. 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; }
  }



回答4:


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.



来源:https://stackoverflow.com/questions/4159943/pass-reference-by-reference-vs-pass-reference-by-value-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!