0

I've got a class that holds a Texture2D like so:

public class TextureData
{
    public Texture2D texture;
}

When I load all of my textures, I handle it through methods like this:

public void LoadAllTextures()
{
    foreach(string s in texturesToBeLoaded)
    {
        TextureData data = new TextureData();
        LoadTexture(s, data.texture);
        // data.texture is still null.
    }
}
public void LoadTexture(string filename, Texture2D texture)
{
    texture = content.Load<Texture2D>(filename);
    // texture now holds the texture information but it doesn't
    // actually retain it when the method ends...why?
}

Am I missing something here? If I change

public void LoadTexture(string filename, Texture2D texture)

To

public void LoadTexture(string filename, out Texture2D texture)

It works fine.


EDIT: Alright so the way I understand it now is this...

public void LoadAllTextures()
{
    foreach(string s in texturesToBeLoaded)
    {
        TextureData data = new TextureData();
        // here, data.texture's memory address == 0x0001
        LoadTexture(s, data.texture /*0x0001*/);
    }
}
public void LoadTexture(string filename, Texture2D texture /* this is now 0x0001 */)
{
    texture = content.Load<Texture2D>(filename);
    // now the PARAMETER is set to 0x0002, not data.texture itself.
}
inline
  • 695
  • 1
  • 7
  • 17
  • possible duplicate of [What is the use passing Class Object using keyword "ref"?????? They are by by default pass by refrence](http://stackoverflow.com/questions/10276808/what-is-the-use-passing-class-object-using-keyword-ref-they-are-by-by-de) – Lucero Aug 15 '12 at 10:14

4 Answers4

3

C# passes variables by value - a copy of the reference is passed but the original variable or field remains untouched. Adding out (or ref) makes it pass by reference, which then causes the original variable/field to be updated.

Lucero
  • 59,176
  • 9
  • 122
  • 152
  • Texture2D is a class, though. It's been my understanding that passing a class (as opposed to a struct) IS passing by reference. – inline Aug 15 '12 at 10:14
  • Well, if you were passing an existing class instance you could make modifications to it; that's correct. However, here you're trying to change the variable holding the reference, not the instance. – Lucero Aug 15 '12 at 10:15
  • Alright. Can you check the edit in my original post and comment on if I'm understanding this correctly? – inline Aug 15 '12 at 10:26
  • @Inlinevoid, yep I think you got it. :) – Lucero Aug 15 '12 at 10:37
  • Awesome, thanks for the help (from everyone else, too. upvotes all around!). – inline Aug 15 '12 at 10:40
1

Lucero's answer is correct - the practical change you would make is to change your methods to work as follows:

public void LoadAllTextures()
{
    foreach(string s in texturesToBeLoaded)
    {
        TextureData data = LoadTexture(s);
        // do something with data here
    }
}

public Texture2D LoadTexture(string filename)
{
    Texture2D texture = content.Load<Texture2D>(filename);
    return texture;
}
tomfanning
  • 9,552
  • 4
  • 50
  • 78
  • Thanks but I have it set up so that I can return a boolean telling me if the texture loading succeeded or failed. The methods themselves are too big so I just typed up some pseudo. – inline Aug 15 '12 at 10:42
1

That is because you are modifying the copy of the reference. Earlier data.texture points to a memory location suppose 048, when you call LoadTexture(s, data.texture); the parameter texture now holds the value 048. In the first line in your method LoadTexture you are assigning it a new memory location, so now texture points to something totally new, but not 048. That is why you don`t see any change.

But if you update any property of texture, you will see the change in original data as well.

Consider the following case:

public class TempClass
{
    public string MyProperty { get; set; }
}

In your Main method you can do:

TempClass tc = new TempClass();
tc.MyProperty = "Some value";
SomeMethod(tc);

Where as your SomeMethod is:

public static void SomeMethod(TempClass temp)
{
    temp = null;
}

Now that will not set the object tc of TempClass to null.

You should see this article by Jon Skeet: Parameter passing in C#

Habib
  • 219,104
  • 29
  • 407
  • 436
1

The confusion probably comes from what it means to pass by reference. In C#, objects are passed by reference. This means if you modify properties of the object in a function, those changes will be reflected in the calling function as well as they both have references to the same object. However, pass-by-reference does NOT mean that if you update the variable to refer to a different object (e.g. by creating a new object) in the function that the variable in the calling function will be updated to refer to the same object. You must use ref or out if this is the behavior you want.

Eric
  • 6,364
  • 1
  • 32
  • 49
  • To follow up on your (now deleted) comment - this is because the reference itself is passed by value, adding `out`/`ref` passes the reference by reference. – Lucero Aug 15 '12 at 10:20
  • @Lucero: Yes, I realize that. That's why I deleted the comment. – Eric Aug 16 '12 at 08:18