Thursday, March 15, 2007

C# Reference types pass by value

(file under “stuff that I knew and forgot but wish I hadn't and probably won't ever again”)

Parameters in C# are, by default, passed by value.

That means that your function cannot modify the value of its arguments. You pass it an int i = 2 and even if internally it does i = 3, once the function returns you still have i == 2.

However for reference types, pass by value does not mean what you might think it means. A reference type is basically a memory address. That memory address is passed (sure enough) by value - the function cannot change the location of your object. But internal to the function the reference type is still pointing to the same location in memory. Thus any changes to the object within the function will be reflected in the calling context - the function will have side effects.

So what do I find in some of our code today?

void function (User user){
    User localUser = user;
    localUser.SomeProperty = "Not the value that you were expecting haha hoho";
}

Hrm. My calling context's value for SomeProperty is not what I was expecting. Seems someone had realised that the reference type was going to cause problems... “I know, I will make a copy of it and change that.” Unfortunately that will not work either. The assignment operator copies the value of the reference type (the memory address) not the object itself. I.e. it is not a deep copy.

How do you fix this? You make a function that performs a deep copy, and call it from within any function that receives your reference type as a parameter.

A good place for this function? A copy constructor. An overloaded constructor in the reference type class that takes one argument - a reference to an object of the same type. Then copies all of the properties to the new instance.

class User{
    public string UserName;
 
    User(User existingUser){
        UserName = existingUser.UserName;
    }
}

How do you enforce the “no messing with my data” rule? Well, the only thing that I can think of is “If you don't want people breaking your toys, don't lend them out” - only let them have a copy.

function(new User(MyUser));

What does explicitly telling a reference type to be passed by reference actually do? Not much as far as I can see.

Would it be nice if passing a reference type by value did something closer to what you might expect? (Could be done by internally making a deep copy of the object at the time of the call) Possibly.

Will I ever forget that “Reference types are always modifiable when passed as parameters”? I wish I could say no.

4 comments:

  1. Ya exactly. I wish we had something like what we have in C++. Automatic call to the copy constructor when you do something like:

    function(MyUser);

    Copy constructor kicks in and creates a copy, so much easier and the programmer does not have to be aware of making a copy everytime :)

    ReplyDelete
  2. public static T DeepCopy [T](T item)
    {
    BinaryFormatter formatter = new BinaryFormatter();
    MemoryStream stream = new MemoryStream();
    formatter.Serialize(stream, item);
    stream.Seek(0, SeekOrigin.Begin);
    T result = (T)formatter.Deserialize(stream);
    stream.Close();
    return result;
    }

    Anjum Rizwi

    ReplyDelete
  3. hi this is answer gave for me

    ReplyDelete
  4. for using Anjum DeepCopy method you need to add the [Serializable] tag to the class

    [Serializable]
    public class MyObject
    {

    }

    noam giladi

    ReplyDelete