tags:

views:

784

answers:

3

I make extensive use of inheritance, polymorphisim, and encapsulation but i just realised that i didn't know the following behavior about scope of an object vs a variable. The difference is best shown with code:

public class Obj
{
    public string sss {get; set;}

    public Obj()
    {
        sss = "0";
    } 
}     

public partial class testScope : System.Web.UI.Page
 {
    protected void Page_Load(object sender, EventArgs e)
    { 
        Obj a = new Obj(); 
        String sss = "0";            
        Context.Response.Write(sss); // 0

        FlipString(sss);
        FlipString(a.sss);
        Context.Response.Write(sss + a.sss); // 0 0

        FlipObject(a);
        Context.Response.Write(a.sss); // 1
        Context.Response.End();
    }

    public void FlipString(string str)
    { str = "1"; }

    public void FlipObject(Obj str)
    { str.sss = "1"; }
}

So I thought that when a variable is passed into a method that changes are limited to the scope of the method. But it appears that if an object is passed into a method that changes to it's properties extend beyond the method.

I could accept this if the rule was that this behavior exists for object and not variables but in .net everything is an object, a string (like the one in the example is System.String) So whats the rule, how can i predict the scope of a parameter that i pass into a method?

A: 

I think that i just figured it out googleing around, some things in .net are "value" types and others are "reference" types, so for value types the value is duplicated when being marshaled into a method, but reference types have a like a pointer, or reference passed into the method which obviously shares the same scope as the parent. So then my question is how can tell if something is a value type or not, i see that structs like ints are all value types but Strings appear to behave like structs even though they are objects System.String?

rizzle
Strings are still reference types, but they're immutable. They don't *actually* behave like structs - they behave like reference types. The only thing that makes them look a bit like structs is that they're immutable, but you can write your own immutable reference types too.
Jon Skeet
The key point is to differentiate between changing a parameter's value to refer to a different object, and changing the contents of an object *referred to* by the parameter.
Jon Skeet
+13  A: 

You never pass an object as an argument - you only ever pass a reference or a value type value. Unless you use the ref keyword, arguments are passed by value - i.e. the initial value of the parameter is the evaluated value of the argument, and changes to the value of the parameter aren't seen by the caller.

However, it's very important to understand that the value of the parameter (for a reference type) is just the reference. If you change the contents of the object that the reference refers to, then that change will be seen by the caller.

It's a topic which deserves more than a few paragraphs - I suggest you read my article about parameter passing in .NET for more information.

Jon Skeet
thanks jon, i'll be sure to accept the answer later in the day rather than early for max rep :)
rizzle
LOL: I wouldn't worry about that - it's not a big deal. A better answer may very well come along.
Jon Skeet
+1 on the mention of a topic that gets too little discussion.
jro
Thanks for a very informative article.
Saif Khan
A: 

A class (Obj in your case) is a reference type, so when you call the function what you're really doing is passing a reference (you can basically think of this as a type-safe pointer) to this object. If you want to prevent changes to mutable objects (i.e. class/reference types), then you need to clone this object before passing it to the appropiate function (or simply consider making it a structure so that it is copied by value).

Noldorin