views:

79

answers:

5

hi, i've some difficult to explain my problem, because i'm also not good in english :|! I've the following code

namespace StighyGames.MyGames {
public class MyGames
{    
...
...
  CarClass myCar = new CarClass(...); 

  Main () {
     MyGames game = MyGames(...);
  }
}

Game is my "main" object (my application).

In my CarClass i've some code ...

Now, inside myCar (object) i would like to call a function (a method) contained the main class MyGames.. the method "GameOver" . This, because, if my car "explode" i've to call the GameOver Method. But GameOver method can't be "child" of myCar ... because GameOver is a method of the game... Ok.. hope to be explained, my question is: "I don't know how to call a method of the main object class"..

Thank you for your help !

+1  A: 

You could:

  1. Modify your CarClass class (which really should be renamed Car) to hold a reference to the Game it belongs to.

  2. Create an Event on the Car class called Explode. The Game class could then register for the Explode event and make sure the GameOver() method gets called from that handler.

Justin Niessner
+1  A: 

You can use the Singleton design pattern on your main class.

Or you can revert the problem, and implement a CheckGameOver in MyGames, that would poll the car for its state. That would be my preferred method, as it reduces dependencies.

jv42
+1  A: 

You can pass a reference to your MyGames instance into your CarClass instance, it's the 'parent' reference. While I would think that you might better architect your game using events and delegates, there's nothing to stop you calling a method on the parent object.

Lazarus
+5  A: 

You have several options.

1) Create an event in CarClass and capture it in MyGames.

2) Use a delegate and pass the function reference to CarClass object

3) Add a property to CarClass of type MyGames (say called "Owner"), and after you create CarClass, assign "this" to it: myCar.Owner=this. So you've created a reference in the CarClass object to its creator, and code in CarClass can directly access the methods of its owner.

Which is the best depends on the situation and how these objects will be used. An event is probably preferred, since it offers the most flexibility. A delegate is less flexible and more efficient than an event, though they really serve slightly different purposes. (An event is really an extension of a delegate). The last one is probably the worst form, generally, since it tightly binds the objects, but it has a time and place.

Here's #1

public class CarClass
{
    // A delegate is a pointer to a function. Events are really a way of late
    // binding delegates, so you need to one of these first to have an event.
    public delegate void ExplodedHandler(CarClass sender);
    // an event is a construct which is used to pass a delegate to another object
    // You create an event based for a delegate, and capture it by
    // assigning the function reference to it after the object is created. 
    public event ExplodedHandler Exploded;
    protected void CarCrash()
    {
       ... do local stuff
       // Make sure ref exists before calling; if its required that something
       //  outside this object always happen as a result of the crash then 
       // handle the other case too (throw an error, e.g.)/
       // See comments below for explanation of the need to copy the event ref
       // before testing against null
       ExplodedHandler tempEvent = Exploded;
       if (tempEvent != null) {
         tempEvent(this);
       } 
    }
}
public class MyGames
{    
...
...
  CarClass myCar = new CarClass(...); 
  myCar.Exploded += new ExplodedHandler(GameOver);
  Main () {
     MyGames game = MyGames(...);
  }
  void GameOver(CarClass sender) {
     // Do stuff

  }
}
jamietre
+1 for event. It's the most sensible option
Matt Ellen
I think GameOver is more a responsability of Game than Car. The car should just say: "I'm exploded!".
bonfo
Very good point, the events are misnamed... correcting.
jamietre
You should change make a copy of the `Exploded` handler and compare *that* to null, instead of doing it the way you are doing it. While it seems unlikely that you will ever remove the `Exploded` handler later, it's still poor practice. See [Eric Lippert: Events and Races](http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx) for explanation.
Brian
I've read that before, though I can't say I've been able to change my habit. I agree it's best practice. But as long as your application never unsubscribes from events, I think it's a fairly minor sin. I like the suggestion in the comments on that link to use an extension method. Anyway - I updated the code since I can't think why someone learning about events shouldn't learn best practice.
jamietre
+1  A: 

As everyone has answered you have several options. But not all the options are equally good.
Here my list.

1) Add an event to the Car object and let the Game register to it.
2) Pass a delegate to the Car object
3) Pass to the Car object a reference to a Game
4) Use static call.

All the answer except the first are "bad" ;)

Here the code. I'm using C# 4.0

public class Car
{
    public event Action<Car> Explode;

    private void OnExplode()
    {
        Explode(this);
    }
}

public class Game
{
    private Car car;


    public Game()
    {
        car = new Car();
        car.Explode += new Action<Car>(NotifyExplosion);
    }

    private void NotifyExplosion(Car car)
    {
        Console.WriteLine("{0} is exploded", car.ToString());
        GameOver();
    }

    private void GameOver()
    {
        Console.WriteLine("GAME OVER");
    }

    static void Main(string[] args)
    {
        Game game = new Game();
    }

}
bonfo
Just a minor bone of contention, I don't think every other way is necessarily bad. Just most likely bad. If, for example, it is a requirement that every Car object cause some external action on a crash, and you explicitly wish to prevent more (or fewer) than a single potential subscriber since a car should never be in more than one game, you might want to use a delegate, and maybe even include it as a required constructor parameter. It would be more efficient and the construct matches the intended functionality better.
jamietre
Yes, off course everthing depends on what you want to achive ;)
bonfo