How do i trigger an event declared in another class? Why doesn't this work?

So my class, UPInputManager, contains this event declaration

    public delegate void MoveToEventHandler(bool queued, Vector3 location);//Called when we click to send a move order
    public static event MoveToEventHandler MoveTo;

I’m attempting to trigger this from a different class, using this:

if (UPInputManager.MoveTo != null)
        {
            UPInputManager.MoveTo(Input.GetButton("Shift"), hit.point);
        }

But it throws an error:
“The event UPInputManager.MoveTo can only appear on the left hand side of += or -= (except when used from within the type ‘UPInputManager’)”

I don’t get this restriction. Shouldn’t making it public allow me to do this? o.o

Just guessing, does it work with brackets after MoveTo()?

if (UPInputManager.MoveTo() != null)

This is what events are for.

Events are special types of delegates that can only be invoked/called from the scope of where it was declared at.

In your case, ‘MoveTo’ can only be called from inside UPInputManager.

That’s what makes it an event, as opposed to a delegate.

If you want this to be called from anywhere, just don’t declare it as an event:

public class UPInputManager
{

    public delegate void MoveToEventHandler(bool queued, Vector3 location);
    public static MoveToEventHandler MoveTo;

}

Of course… this also breaks encapsulation. Any object could set the delegate to null at any moment.

Note - I’d also like to point out you’re breaking the ‘event’ design. .Net doesn’t require it, but events are usually shaped like some EventHandler is:

delegate void EventHandler(object sender, EventArgs e);

Usually a custom event with special args will have a type that inherits from EventArgs and has the desired extra data as properties of that object.

This way an event handler can take that base shape of EventHandler and be attached to any event.

Of course, as stated, this isn’t forced… just strongly suggested by the .Net designers.

You should check out this article in full about events:
https://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx

You can see the strong suggestion here:

You can also find the answer to your original question as this statement:

6 Likes

I think the crux of your issue is a misunderstanding of the use for events.

Consider this analogy: Think of objects as people in your life. Sometimes you want to call them up and ask them to do something: “Hi mom, I’m heading over now so you can put the stuff outside and I’ll pick it up.” In very generic programming terms, we call this sending a message, and in C# we send messages through function calls.

This kind of messaging works some of the time but what if we have something for mom? I don’t want to think about how this conversation might end: “Hi mom, it me. I have that thing you need and am ready to put it outside. Are you ready to come get it? No? Okay…” five minutes later “Hi mom, it me. I have that thing you need and am ready to put it outside. Are you ready to come get it? No? Okay…” five minutes later

So what makes more sense? How about: “Hi mom, it me. I have that thing you need and am ready to put it outside. Just let me know when you are coming to get it.” This is still a message, but I’m no longer calling a function. I’m telling my mom to call my function when she is ready. This is an event. Obviously it doesn’t make sense if I now try to call my mom up and tell her: “You need to call me now because you’re coming over to get that thing I have for you.” Nor would it make any sense for anyone to tell her that. It is up to her to decide when that “event” occurs. That is why you can only call an event from the class that defines it.

Think of events as the mathematical “dual” to functions. We call functions, but events call us.

That said, there might be a legitimate reason for me to be able to tell someone else to trigger an event. Here’s an example I dreamed up.

class Operator
{
  public delegate void AgentInTroubleEvent(object sender, AgentEventArgs e);

  public event AgentInTroubleEvent OnAgentInTrouble;

  public void ReportAgentUnderFire(Agent agent)
  {
    if (OnAgentInTrouble != null)
      OnAgentInTrouble(this, new AgentEventArgs(agent));
  }
}

class Agent
{
  private Operator headquarters;
  public Agent(Operator headQuaters)
  {
    this.headquarters = headQuaters;
    headQuaters.OnAgentInTrouble += AssistAgent;
  }
  public void AssistAgent(object headQuaters, AgentEventArgs agentInfo)
  {
    // move to assist the agent that needs help!
  }
  public void CallForHelp()
  {
    headquarters.ReportAgentUnderFire(this);
  }
}

class AgentEventArgs : EventArgs
{
  public Agent Agent {get; set;}
  public AgentEventArgs(Agent agent)
  {
    this.Agent = agent;
  }
}
5 Likes