Anachronist
Anachronist

Reputation: 1102

C# user defined callbacks to a method in a different class

I've been looking for several days for the solution to a trivial problem in C or C++ but seemingly impossible in C#.

Another programmer creates class A. An event handler method in class A needs to call a method in my class B to process the event. Depending on the type of event, that method in class B needs to callback a method in class A, and that method has an arbitrary name or may not even exist.

This is simple in C; you just have a pointer to the callback function and call it indirectly if it isn't null. I don't know how to do indirect method calls in C#. Here's an example of some code illustrating the problem.

public class A: ZZZ { // this class is NOT under my control
   private b = new B(this);

   public void myCallback(C x) {
      // do something
   }

   // Elsewhere in the application expects a protected
   // override method to exist in *this* class A to handle
   // an event. But we want a method in class B to handle
   // it and then call myCallback depending on the type of event

   protected override void handle_some_event(event e) {
      // doesn't work -- how do I pass a "pointer" to the callback??
      b.handle_event(e, myCallback);
   }
}


public class B {    // this class IS under my control
   private A base;

    public B(A a) {
       base = a; // allows for calling methods in class A from class B
    }

    public handle_event(event e, ??? callback pointer ??? cback) {
       // do stuff...
       // then do the callback
       // cback(); // this won't work
       base.myCallback(); // this WILL work but only if I hard-code "myCallback"
    }    
}

The problem is that class B is the one I'm writing, and class A is authored by someone else who will be using my class B. That someone else has the option of not defining a callback at all, or creating one with any arbitrary name. Class B needs to know somehow what that is and how to access it. In C or C++ the other programmer could simply pass a pointer to his callback function. Is that possible in C#?

Upvotes: 1

Views: 3075

Answers (3)

Anachronist
Anachronist

Reputation: 1102

Here is the solution I ended up with, based on the code in my initial post

public class A: ZZZ { // this class is NOT under my control
   private b = new B(this);
   b.UserCallback = myCallback;

   static void myCallback(C x) {
      // do something
   }

   // Elsewhere in the application expects a protected
   // override method to exist in *this* class A to handle
   // an event. But we want a method in class B to handle
   // it and then call myCallback depending on the type of event

   protected override void handle_some_event(event e) {
      b.handle_event(e);
   }
}

public delegate void usercallback(Z z); // declare OUTSIDE both classes

public class B {    // this class IS under my control
   public usercallback UserCallback = defaultCallback;
   static void defaultCallback(Z z) { /* do nothing */ }

   public handle_event(event e) {
       // do stuff...
       // then do the callback
       UserCallback(z);
   }    
}

What got me stuck for a while is wrapping my head around the fact that a delegate declaration is analogous to a C function prototype, and that a delegate may be used as a declaration type in a class.

Upvotes: 0

CodingGorilla
CodingGorilla

Reputation: 19852

You want to pass an Action<T> to the handle_some_event you can do that like this:

public handle_some_event(event e, Action<C> cback) 
{
   // Do stuff
   if(cback != null)
       cback(myC);
}

Your class B in fact doesn't need to know anything at all about class A, it just needs an Action delegate to execute, the rest is irrelevant.

Upvotes: 2

Chandu
Chandu

Reputation: 82933

You can use Action delegate to refer to the callback.

Check this URL for more info: http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

Change you class B to : public class B { private A base;

    public B(A a) {
       base = a; // allows for calling methods in class A from class B
    }

   //#################### NOTE THE CHANGE HERE ##################//
    public handle_some_event(event e, Action<C> cback) {
       // do stuff...
       // then do the callback
       cback(x); // this will work assuming you have x defined somewhere in B
    }    
}

Upvotes: 0

Related Questions