Thread: Object passed to method as parameter

  1. #1
    Registered User elodman's Avatar
    Join Date
    Sep 2011
    Posts
    3

    Object passed to method as parameter

    Greetings.

    Can you explain why
    1) method nochange() doesn't change the object argument, although the object is of reference-type passed by value?
    2) method change2() can change the field of the object passed without REF?

    More comments in the code below.

    Thanx. Bye.

    Code:
    
    usingSystem;
    usingSystem.Collections.Generic;
    usingSystem.Linq;
    usingSystem.Text;
    
    namespace ref_obj
    {
        class clsTest
        {
            publicint a;
    
            public clsTest(int i)
            {
                a = i;
            }
    
            //this will not change the argument
            publicvoid noChange(clsTest obj)
            {
                clsTest newObj =new clsTest(0);
                obj = newObj;// this has no effect outside of noChange()
            }
    
            //this will change what the argument refers to
            publicvoid change1(ref clsTest obj)
            {
                clsTest newObj =new clsTest(0);
                obj = newObj;//this affects the calling argument
            }
    
            // changing Object argument field without REF
            publicvoid change2(clsTest obj)
            {
                obj.a =33;// this changes a field of the called argument
            }
        }
    }
    
    
    namespace ref_obj
    {
        classProgram
        {
            staticvoidMain(string[] args)
            {
                clsTest ob =new clsTest(100);
    
                Console.WriteLine("ob.a before call: "+ ob.a);
    
                ob.noChange(ob);
                Console.WriteLine("ob.a after nochange call: "+ ob.a);
    
                ob.change1(ref ob);
                Console.WriteLine("ob.a after change1 call: "+ ob.a);
    
                ob.change2(ob);
                Console.WriteLine("ob.a after change2 call: "+ ob.a);
    
                Console.ReadLine();
            }
        }
    }
    OUTPUT:


    ob.a before call: 100
    ob.a after call to NoChange(): 100
    ob.a after call to Change1(): 0
    ob.a after call to Change2(): 33

  2. #2
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    I'm sure everybody here can, the question is can you? Go on, be a devil and have a bash.

  3. #3
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    It can boggle the mind, I admit. When I first started learning C++, references took a while to set in. And C# can equally or more confusing since its distinction between reference and value types is so central to the use you make of the language.

    Elodman, that behavior is by design. That is, it's intentional. The rule is as follows:

    Quote Originally Posted by MSDN
    A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref (or out) keyword. For simplicity, the following examples use ref.
    As for value types:

    Quote Originally Posted by MSDN
    A value-type variable contains its data directly as opposed to a reference-type variable, which contains a reference to its data. Therefore, passing a value-type variable to a method means passing a copy of the variable to the method. Any changes to the parameter that take place inside the method have no affect on the original data stored in the variable. If you want the called method to change the value of the parameter, you have to pass it by reference, using the ref or out keyword. For simplicity, the following examples use ref.
    Last edited by Mario F.; 09-21-2011 at 11:18 AM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    I guess I haven't reached the 'ref' keyword yet. I thought everything (except base types (int, double, etc)) were reference passes in C#.


    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Quote Originally Posted by quzah View Post
    I guess I haven't reached the 'ref' keyword yet. I thought everything (except base types (int, double, etc)) were reference passes in C#.
    Quzah.
    For the most part that's true. structs are also value types. Using the 'ref' keyword with a reference type is meaningless, but legal.
    If you understand what you're doing, you're not learning anything.

  6. #6
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by itsme86 View Post
    Using the 'ref' keyword with a reference type is meaningless, but legal.
    Meaningless is not the correct word. Passing a reference type by reference (with the ref keyword) allows you to change the reference to a new object and persist that change outside the local scope. It's the only way you can do it.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Essentially the gurus took away pointers so they could make everything a pointer and confuse more people in the process. It is quite confusing at first and gets really confusing when you want to copy the object in question without referring to the original object. I had to wrap my head around this b/c I kept altering the original object thinking I was altering a copy and vice versa. It gets worse when you begin to have references that have references to objects that do not go out of scope which then causes the other object with a reference to it to not go out of scope and you end up hogging tons of memory without even realizing what is going on.

    Value types are interesting beasts but for me they are also the easiest to understand. Reference types appear simple at first and then you realize that you can really make a mess of things by handing out refs everywhere.
    Last edited by VirtualAce; 09-21-2011 at 06:10 PM.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    class Foo
    {
        Bar baz;
    
        Foo( Bar b ) { baz = b; }
        void Goo( Bar b ) { b = new Bar(); }
        void Hoo( ) { Goo( this.baz ); }
    }
    So Hoo won't set this.baz through Goo because it's not a reference? I don't know, that doesn't seem right. These are actually pointers (references), not value passes:
    Code:
    void Ioo( Bar b )
    {
        b.c = d;
    }
    So you are saying that 'ref' basically makes a pointer to a pointer? That doesn't seem right, and while I'd have to look, I'm pretty sure I have used new in a method to fill something passed as an argument and had it work.


    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by quzah View Post
    So Hoo won't set this.baz through Goo because it's not a reference? I don't know, that doesn't seem right.
    It's the thing you'll have to work your head around in C#. The ref keyword essentially serves two different purposes depending on whether you are passing a value-type or a reference type.

    Value types:
    - Works as a means to persist changes to member data across method calls.

    Reference types:
    - Works as a means to persist changes to the referenced object across method calls.

    Quote Originally Posted by quzah View Post
    So you are saying that 'ref' basically makes a pointer to a pointer?
    Because of the above we then have:

    No, if you are passing a value type. With these, the ref keyword behaves much like a reference in C++ or a const pointer in C.

    A sort of yes, for reference types. If you consider reference-types equivalent to pointers (which they are sort of. You do not dereference a reference-type but the reference (the local variable) exist on the stack while the actual class object was allocated on the heap), passing by reference could be seen as a sort of pointer to pointer. However the actual requirement to do this is to be able to change what object the local variable points to and persist that data. You don't have that type of limitation with C pointers.

    Quote Originally Posted by quzah View Post
    while I'd have to look, I'm pretty sure I have used new in a method to fill something passed as an argument and had it work
    It will always work for the local scope. But the change won't persist once you fall out of it.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  10. #10
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    I'm avoid mentioning C++ references because you don't have a C++ background, is that right? But if you do, here's a way I prefer to use when explaining the ref keyword applied to reference types (and reference types only) in C#:

    Reference types in C# are more akin to C++ references, in that changes to member data is persisted across method calls. The ref keyword in C# however allows one to bypass C++ references limitations, in that we can use it to change the object a reference variable points to after being allocated.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  11. #11
    Registered User elodman's Avatar
    Join Date
    Sep 2011
    Posts
    3
    Thank you Mario F., and others.

    I try to accept the parameter process as it is, thanx for your sources.

  12. #12
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Quote Originally Posted by quzah View Post
    So you are saying that 'ref' basically makes a pointer to a pointer? That doesn't seem right, and while I'd have to look, I'm pretty sure I have used new in a method to fill something passed as an argument and had it work.
    If the object is a value type, the 'ref' keyword passes it as a reference to a value.

    If the object is a reference type, the 'ref' keyword passes it as a reference to a reference - behind the scenes it's basically implemented as a pointer to a pointer.

    Try this:
    Code:
    using System;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                int i;
                RefType j = new RefType();
                i = 23;
                j.Value = 42;
    
                Console.WriteLine("Start:       i = {0}, j = {1}", i, j.Value);
                IntByVal(i);
                Console.WriteLine("IntByVal:    i = {0}, j = {1}", i, j.Value);
                IntByRef(ref i);
                Console.WriteLine("IntByRef:    i = {0}, j = {1}", i, j.Value);
                ObjByVal(j);
                Console.WriteLine("ObjByVal:    i = {0}, j = {1}", i, j.Value);
                ObjByRef(ref j);
                Console.WriteLine("ObjByRef:    i = {0}, j = {1}", i, j.Value);
                Console.WriteLine("Press Enter to continue");
                Console.Read();
            }
    
            static void IntByVal(int i)
            {
                i = 30;
            }
    
            static void IntByRef(ref int i)
            {
                i = 97;
            }
    
            static void ObjByVal(RefType j)
            {
                j.Value = 36;
                j = new RefType();
                j.Value = 128;
            }
    
            static void ObjByRef(ref RefType j)
            {
                j.Value = 768;
                j = new RefType();
                j.Value = 90210;
            }
    
        }
    
        class RefType
        {
            public int Value { get; set; }
        }
    
    }
    IntByVal of course passes an integer by value, so it doesn't change the value of i or j in the main tag; only the local copy changes.

    IntByRef changes the value of i in the main method because it has a reference.

    ObjByVal sets j to have a value of 36. Changing its local j to refer to a new object does not change the caller.

    ObjByRef sets j to have a value of 90210; changing the local j to refer to a new object does change the caller's variable also named j, because the reference itself was passed by reference.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Finding the name of the object parameter
    By circuitbreaker in forum C++ Programming
    Replies: 7
    Last Post: 02-11-2008, 11:27 PM
  2. A pointer to an object's function as a parameter
    By wiiire in forum C++ Programming
    Replies: 2
    Last Post: 09-30-2007, 10:38 PM
  3. Remote Method return object instance?
    By BigDaddyDrew in forum C# Programming
    Replies: 0
    Last Post: 07-20-2004, 11:19 AM
  4. Comparing A Struct To A Passed Parameter
    By Anonymous in forum C++ Programming
    Replies: 1
    Last Post: 11-09-2002, 11:38 PM
  5. Accesing private data from method of another object
    By QuickSilver in forum C++ Programming
    Replies: 9
    Last Post: 01-16-2002, 04:15 AM

Tags for this Thread