user3597549
user3597549

Reputation: 35

C# object loses it's reference and becomes empty

Here is the simplified code of my classes:

public class Game
{
    World world;
    DataManager dataManager;
    public Game()
    {
        world = new World();
        dataManager = new DataManager();
    }

    public void Run()
    {
        Menu mainMenu = new Menu(dataManager,world);
        //world = dataManager.LoadFile("Games\\test game.xml");
        //the commented line above is correcting my bug but I don't want
        //to do it that way.
        List <Location> locs = world.GetAllLocations();
        //when the debug mode arrives at this point, world is empty.
    }
}

public class Menu
{
    DataManager dataManager ;
    World world;
    public Menu(DataManager _dataManager, World _world)
    {
        this.dataManager = _dataManager;
        this.world = _world;
        world = dataManager.LoadFile("Games\\test game.xml");
        //the world is filled correctly here above.
    }
 }

Both classes are sharing the same namespace. My dataManager fill the world with an xml, which is perfectly working. the world should be the reference from the game.world property but it seems to become empty as soon as we come back in the Game class...

I really don't understand while the program behave that way. Here is the complete source if you need more:

https://github.com/mikyjax/TextAdventureGameEditor/tree/master/Text%20Adventure%20Engine

Upvotes: 3

Views: 897

Answers (2)

Igor
Igor

Reputation: 62213

That is not how references work.

  1. new Menu(dataManager,world); <= you call the constructor and pass in the world instance created in the constructor (this is not the same as passing in a reference).
  2. this.world = dataManager.LoadFile("Games\\test game.xml") <= A new instance is created (so new pointer) and assigned to the local variable world. What does NOT happen is that the calling method in run now share the same world instance, that is still null.

If that is what you intended you must use the ref keyword (or out).

public Menu(DataManager _dataManager, ref World _world)

and call it with

new Menu(dataManager,ref world);

That said this is bad practice on 2 levels.

  1. You should not have side effects in your constructor
  2. If you are creating an object for use outside of the object (like in a factory) you should have a dedicated method just for that and then have that object returned as the return of the method.

public class Menu {
    DataManager dataManager ;
    World world;
    public Menu(DataManager _dataManager)
    {
        this.dataManager = _dataManager;
    }

    public World CreateWorld() {
        if(this.world == null)
            this.world = dataManager.LoadFile("Games\\test game.xml");
        return this.world;
    }
}


public class Game {
    World world;

    public void Run()
    {
        Menu mainMenu = new Menu(dataManager);
        this.world = mainMenu.CreateWorld();
    }
}

Upvotes: 4

Patrick Artner
Patrick Artner

Reputation: 51623

Your code makes something akin to:

A = B
A = C

and then you wonder why B is not C as well: you set the Menu.World = _world and then rewrite Menu.Wold to be what you load from the xml: _world is unmodified by it.

Why has the Menu constructor to populate the world at all - thats not really one its sole responsibility - is it?

I would rename your static LoadFile to CreateWorld(..filename..) and call that inside the Run method before creating the Menu. That way you can give the prepared World to the Menu constructor.

What I am still wondering about is, why ever a menu needs access to your raw world data ...

Upvotes: 1

Related Questions