locked
Use of "ref" keyword for reference types? RRS feed

  • Question

  • One of my collegue started a discussion regarding ref keyword in C# and I brought up a small sample, which caused quite a confusion- Why is "ref" used for reference types? Here is the sample.

      class Program
      {
        static void Main(string[] args)
        {
          int[] i = { 1, 2, 3, 4 };
    
          //Will output "1
          Console.WriteLine("Before : " + i[1].ToString());
    
          //Calling a method (*NOT* using ref keyword)..So ideally it shouldn't matter what is being changed
          new Test().Modify(i);
    
          //Should output the same "1", as we are not using the ref keyword here....
          Console.WriteLine("After : " + i[1].ToString());          
          //But it outputs "5", which is modified internally in an array
    
          Console.ReadLine();
          
        }
      }
    
      class Test
      {
    
        public void Modify(int[] i)
        {
          if ((i != null) && i.Length > 2)
            i[1] = 5;
        }
        
      }
    

    In the above sample, even if I dont use the ref keyword, the value is modified for the reference type (here it is int[]). Why is it so? Any good explanation is greatly appreciated.

     

    Monday, April 25, 2011 2:52 PM

Answers

  • Keep in mind that C# is pass-reference-by-value by default.  That means that whenever you pass a reference type into a method, you are passing a copy of the reference (in C++ terms this is analogous to passing a pointer to the object, and the pointer gets copied).  In this case, both the original reference and the reference parameter point to the same object, so changing the object it refers to does not alter the original object.

    The only time you need the ref modifier in C# is when:

    • You want to change the value of a value parameter (number, char, struct, etc)
    • You want to change where the passed in reference to a reference type points to.

    For example:

     

    <pre>// this will not work, because you are changing the copied reference
    // and not the original reference
    static void SetToNewString(string oldString)
    {
     // this modifies oldString, but not the argument passed in.
     oldString = "New String";
    }
    
    static void SetToNewString2(ref string oldString)
    {
     // this does modify the original argument passed in, because
     // we are altering the original reference and not the copy
     oldString = "New String";
    }
    
    
    static void Main()
    {
     string myString = "Old String";
    
     // does not work, myString still equals Old String because we
     // modified the copy reference, not the original reference
     SetToNewString(myString);
    
     // works, myString now equals New String because we modified
     // the original reference
     SetToNewString2(myString);
    }
    

    And to your example, you aren't modifying what i refers to, just the contents of i.  Since i points to the same thing as the original, you can do this with reference types.  However, if you wanted to change where i refers to (ie make i refer to a different object than the one passed in) -- THAT is when you need ref or out keywords.  Make sense?


    James Michael Hare

    Blog: http://www.geekswithblogs.net/BlackRabbitCoder

    Twitter: @BlkRabbitCoder

    There are 10 kinds of people in the world: those who know binary and those who don't...



    • Proposed as answer by Evan Machusak Monday, April 25, 2011 3:08 PM
    • Marked as answer by iam_venny Monday, April 25, 2011 3:25 PM
    Monday, April 25, 2011 2:59 PM

All replies

  • Keep in mind that C# is pass-reference-by-value by default.  That means that whenever you pass a reference type into a method, you are passing a copy of the reference (in C++ terms this is analogous to passing a pointer to the object, and the pointer gets copied).  In this case, both the original reference and the reference parameter point to the same object, so changing the object it refers to does not alter the original object.

    The only time you need the ref modifier in C# is when:

    • You want to change the value of a value parameter (number, char, struct, etc)
    • You want to change where the passed in reference to a reference type points to.

    For example:

     

    <pre>// this will not work, because you are changing the copied reference
    // and not the original reference
    static void SetToNewString(string oldString)
    {
     // this modifies oldString, but not the argument passed in.
     oldString = "New String";
    }
    
    static void SetToNewString2(ref string oldString)
    {
     // this does modify the original argument passed in, because
     // we are altering the original reference and not the copy
     oldString = "New String";
    }
    
    
    static void Main()
    {
     string myString = "Old String";
    
     // does not work, myString still equals Old String because we
     // modified the copy reference, not the original reference
     SetToNewString(myString);
    
     // works, myString now equals New String because we modified
     // the original reference
     SetToNewString2(myString);
    }
    

    And to your example, you aren't modifying what i refers to, just the contents of i.  Since i points to the same thing as the original, you can do this with reference types.  However, if you wanted to change where i refers to (ie make i refer to a different object than the one passed in) -- THAT is when you need ref or out keywords.  Make sense?


    James Michael Hare

    Blog: http://www.geekswithblogs.net/BlackRabbitCoder

    Twitter: @BlkRabbitCoder

    There are 10 kinds of people in the world: those who know binary and those who don't...



    • Proposed as answer by Evan Machusak Monday, April 25, 2011 3:08 PM
    • Marked as answer by iam_venny Monday, April 25, 2011 3:25 PM
    Monday, April 25, 2011 2:59 PM
  • That clears by blues. Thanks James

    Monday, April 25, 2011 3:25 PM
  • No problem!  Glad I could help!

    James Michael Hare

    Blog: http://www.geekswithblogs.net/BlackRabbitCoder

    Twitter: @BlkRabbitCoder

    There are 10 kinds of people in the world: those who know binary and those who don't...

    Monday, April 25, 2011 3:46 PM
  • Hi James,

    Arrays are reference types (Ref:http://stackoverflow.com/questions/1113819/arrays-heap-and-stack-and-value-types), so nothing wrong in your code, your array is a reference type so  it will be a call by ref only , any change you do with reference types it will be reflected back, In my opinion we should use ref key word only with Value types to get the changes reflected(Call By Reference) as by default for value types the call will by value.

    I found one use of using ref key word with:   if we are using ref keyword with reference types then it will be helpful to avoid creating a new copy of the instance and uses the same copy of memory created earlier. For example:

    class Program
        {

            static void Main(string[] args)
            {

             Class1 c1 = new Class1();
                
                c1.X = 10;

                change(c1);

                Console.WriteLine(c1.X);

                changeRef(ref c1);

                Console.WriteLine(c1.X);

             }

    public static void change(Class1 c1)
            {
                c1 = new Class1();// here a new copy of Calss1 will get created , the change wont get reflected back.
                c1.X = 20;

                
            }

    public static void changeRef(ref Class1 c1)
            {
                C1 = new Class1(); // Even we are trying to instantiate it again, the same memory copy is assigned because we used Ref keyword.
                c1.X = 30;
            }

    }

        class Class1
        {
            public int X;
        }

    Output:

    10
    30

    Hope this will hep.


    • Edited by Fanendra Thursday, February 20, 2014 11:38 AM
    Thursday, February 20, 2014 11:27 AM