locked
Passing objects by ref vs by value RRS feed

  • Question

  • I was reading here http://www.yoda.arachsys.com/csharp/parameters.html that when you pass a parameter by value a new storage location is created for it. 

    My question is: Say I have an object, a reference type, with a lot of properties, lets call this object Customer.  So this object has a properties for name, city, phone, and so on.  If I pass this object from method to method by value, I am assuming a new memory location will be created for it each time it is passed and there for all its properties as well?  If this is true, is it better to pass objects by reference when possible to avoid the overhead of creating a new storage location in memory, or is this overhead so minuscule it does not really matter?
    Tuesday, April 21, 2009 12:58 AM

Answers

  • The only difference really between passing a reference type by reference or by value, is that if you were to assign the variable again to, let's say, another instantiated version of the object, you'll also change the reference in the calling code.  Here's an example. Notice that after the call to "ByReference" the hash code to the same variable has changed.  The ByReference method has actually changed the value variable outside the method and instructed it to point to another instance of object.  The ByValue method does not do this.  While the pointer is copied, the original pointer outside the method remains the same:

    using System;

     

    namespace ConsoleApplication1

    {

        class Program

        {

            static void Main(string[] args)

            {

                object value = new object();

                Console.Write("ByReference... Before: {0}", value.GetHashCode());

                ByReference(ref value);

                Console.WriteLine("  After: {0}", value.GetHashCode());

                value = new object();

                Console.Write("ByValue    ... Before: {0}", value.GetHashCode());

                ByValue(value);

                Console.WriteLine("  After: {0}", value.GetHashCode());

                Console.ReadLine();

            }

     

            static void ByReference(ref object value)

            {

                value = new object();

            }

     

            static void ByValue(object value)

            {

                value = new object();

            }

        }

    }

     

     


    David Morton - http://blog.davemorton.net/
    • Proposed as answer by Guo Surfer Thursday, April 23, 2009 6:21 AM
    • Marked as answer by Guo Surfer Saturday, April 25, 2009 4:13 PM
    Wednesday, April 22, 2009 1:57 PM
    Moderator
  • Food for thought.
    ValueTypes are stored on the "stack".
    ReferenceTypes are stored on the "managed heap".

    Passing "by value" means passing a pointer to a copy of the value on the stack. 
    Passing "by reference" means passing a pointer to the managed heap.

    Stacks and Heaps.

    Imagine a stack of plates, on which you place plates of data.  There are two such stacks used by .NET.  One is called the managed heap, which is used by reference types.  The other stack is a smaller one, simply called the stack and it is used for objects of fixed size like value types and memory pointers.  As you create variables for storage, the type determines where they are stored.  Your methods, functions and subs gain access to the data.   

    Identity is determined and defined as the actual storage location.  Equivalence is determined and defined as the data stored at the actual storage location.  That is a subtle, yet significant difference.  Identity is used to describe if objects are identical.  Equivalence is used to describe if objects are equal. 

    Value Types.

    These are basically all of your numbers.  String class is a special reference type that behaves as if it were a value type.  To realize this behavior, strings are treated differently from reference types, and value types, when it comes to memory allocation.  Value types consume a fixed amount of memory.  Memory pointers are actually Integer types, which also have a fixed size. 

    Consider this code using integer variables. 

    a = 1
    b = 2
    c = a 

    The variable a and c are equivalent but not identical.  They each store the same value in memory, but store their data in different locations. 

    Reference Types.

    These are basically everything else.  Reference types are for objects or any size, or varying size.  The name comes from how they are treated.  A reference, or memory pointer, is used to identify the object's location on the managed heap.  These references, or pointers, can be used on the stack as if they were value types.  Pointers are fixed in size.  This is how strings are referenced, but there memory storage is immutable.  That means it is not destroyed. 

    Consider this code using reference variables, of type Class1. 

    a = new Class1
    b = new Class1
    c = a 

    The variables store pointers to locations, objects which are placed on the managed heap.  The actual pointers go onto the stack.  The variables a and c are equivalent, and they are identical.  The variable c is assigned the same pointer value as the variable a.  The variables a and b are equivalent but not identical!

    Hope this starts a brainstorm.

    Rudedog   =8^D 





    Mark the best replies as answers. "Fooling computers since 1971."
    • Proposed as answer by Guo Surfer Thursday, April 23, 2009 6:20 AM
    • Marked as answer by Guo Surfer Saturday, April 25, 2009 4:13 PM
    Wednesday, April 22, 2009 10:30 PM
    Moderator
  • If your object is a struct, you will be creating a new block of memory on the stack space of the method.  The space required will be the space required to store all of the fields (including auto-property backing fields) of the struct.

    If you pass a class to a function, things are different.

    The class is passed as a reference, so you're actually passing a single pointer (reference) to memory, since the class is a reference type.  The method's stack space will allocate new space for this reference, but it's only the size of the reference (one IntPtr - either 32 or 64 bytes depending on OS).  The reference will still point to your original object, so all of the properties, fields, etc will be changable by your method.

    In your case, you'll only create a new IntPtr on the stack - so 32/64 bytes.  There is no copy of your object.  If your object was a struct, though, you'd copy the entire thing to the method.

    • Proposed as answer by Guo Surfer Thursday, April 23, 2009 6:21 AM
    • Marked as answer by Guo Surfer Saturday, April 25, 2009 4:13 PM
    Tuesday, April 21, 2009 1:04 AM
    Moderator

All replies

  • If your object is a struct, you will be creating a new block of memory on the stack space of the method.  The space required will be the space required to store all of the fields (including auto-property backing fields) of the struct.

    If you pass a class to a function, things are different.

    The class is passed as a reference, so you're actually passing a single pointer (reference) to memory, since the class is a reference type.  The method's stack space will allocate new space for this reference, but it's only the size of the reference (one IntPtr - either 32 or 64 bytes depending on OS).  The reference will still point to your original object, so all of the properties, fields, etc will be changable by your method.

    In your case, you'll only create a new IntPtr on the stack - so 32/64 bytes.  There is no copy of your object.  If your object was a struct, though, you'd copy the entire thing to the method.

    • Proposed as answer by Guo Surfer Thursday, April 23, 2009 6:21 AM
    • Marked as answer by Guo Surfer Saturday, April 25, 2009 4:13 PM
    Tuesday, April 21, 2009 1:04 AM
    Moderator
  • The only difference really between passing a reference type by reference or by value, is that if you were to assign the variable again to, let's say, another instantiated version of the object, you'll also change the reference in the calling code.  Here's an example. Notice that after the call to "ByReference" the hash code to the same variable has changed.  The ByReference method has actually changed the value variable outside the method and instructed it to point to another instance of object.  The ByValue method does not do this.  While the pointer is copied, the original pointer outside the method remains the same:

    using System;

     

    namespace ConsoleApplication1

    {

        class Program

        {

            static void Main(string[] args)

            {

                object value = new object();

                Console.Write("ByReference... Before: {0}", value.GetHashCode());

                ByReference(ref value);

                Console.WriteLine("  After: {0}", value.GetHashCode());

                value = new object();

                Console.Write("ByValue    ... Before: {0}", value.GetHashCode());

                ByValue(value);

                Console.WriteLine("  After: {0}", value.GetHashCode());

                Console.ReadLine();

            }

     

            static void ByReference(ref object value)

            {

                value = new object();

            }

     

            static void ByValue(object value)

            {

                value = new object();

            }

        }

    }

     

     


    David Morton - http://blog.davemorton.net/
    • Proposed as answer by Guo Surfer Thursday, April 23, 2009 6:21 AM
    • Marked as answer by Guo Surfer Saturday, April 25, 2009 4:13 PM
    Wednesday, April 22, 2009 1:57 PM
    Moderator
  • Food for thought.
    ValueTypes are stored on the "stack".
    ReferenceTypes are stored on the "managed heap".

    Passing "by value" means passing a pointer to a copy of the value on the stack. 
    Passing "by reference" means passing a pointer to the managed heap.

    Stacks and Heaps.

    Imagine a stack of plates, on which you place plates of data.  There are two such stacks used by .NET.  One is called the managed heap, which is used by reference types.  The other stack is a smaller one, simply called the stack and it is used for objects of fixed size like value types and memory pointers.  As you create variables for storage, the type determines where they are stored.  Your methods, functions and subs gain access to the data.   

    Identity is determined and defined as the actual storage location.  Equivalence is determined and defined as the data stored at the actual storage location.  That is a subtle, yet significant difference.  Identity is used to describe if objects are identical.  Equivalence is used to describe if objects are equal. 

    Value Types.

    These are basically all of your numbers.  String class is a special reference type that behaves as if it were a value type.  To realize this behavior, strings are treated differently from reference types, and value types, when it comes to memory allocation.  Value types consume a fixed amount of memory.  Memory pointers are actually Integer types, which also have a fixed size. 

    Consider this code using integer variables. 

    a = 1
    b = 2
    c = a 

    The variable a and c are equivalent but not identical.  They each store the same value in memory, but store their data in different locations. 

    Reference Types.

    These are basically everything else.  Reference types are for objects or any size, or varying size.  The name comes from how they are treated.  A reference, or memory pointer, is used to identify the object's location on the managed heap.  These references, or pointers, can be used on the stack as if they were value types.  Pointers are fixed in size.  This is how strings are referenced, but there memory storage is immutable.  That means it is not destroyed. 

    Consider this code using reference variables, of type Class1. 

    a = new Class1
    b = new Class1
    c = a 

    The variables store pointers to locations, objects which are placed on the managed heap.  The actual pointers go onto the stack.  The variables a and c are equivalent, and they are identical.  The variable c is assigned the same pointer value as the variable a.  The variables a and b are equivalent but not identical!

    Hope this starts a brainstorm.

    Rudedog   =8^D 





    Mark the best replies as answers. "Fooling computers since 1971."
    • Proposed as answer by Guo Surfer Thursday, April 23, 2009 6:20 AM
    • Marked as answer by Guo Surfer Saturday, April 25, 2009 4:13 PM
    Wednesday, April 22, 2009 10:30 PM
    Moderator
  • Thanks the best explaination to By Refs and By Vals I've heard of.
    Thanks,


    The focused one.
    Saturday, April 25, 2009 2:47 AM