Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Callbacks in C#

Tags:

c#

.net

callback

I want to have a library that will have a function in it that accepts an object for it's parameter.

With this object I want to be able to call a specified function when X is finished. The function that will be called is to be specified by the caller, and X will be done and monitored by the library.

How can I do this?

For reference I'm using C# and .NET 3.5

like image 372
Malfist Avatar asked Mar 20 '09 20:03

Malfist


2 Answers

Two options for you:

  1. Have the function accept a delegate (Action for a callback that doesn't return anything, Func for one that does) and use an anonymous delegate or Lambda Expression when calling it.

  2. Use an interface

Using a delegate/lambda

public static void DoWork(Action processAction)
{
  // do work
  if (processAction != null)
    processAction();
}

public static void Main()
{
  // using anonymous delegate
  DoWork(delegate() { Console.WriteLine("Completed"); });

  // using Lambda
  DoWork(() => Console.WriteLine("Completed"));
}

If your callback needs to have something passed to it, you can use a type parameter on Action:

public static void DoWork(Action<string> processAction)
{
  // do work
  if (processAction != null)
    processAction("this is the string");
}

public static void Main()
{
  // using anonymous delegate
  DoWork(delegate(string str) { Console.WriteLine(str); });

  // using Lambda
  DoWork((str) => Console.WriteLine(str));
}

If it needs multiple arguments, you can add more type parameters to Action. If you need a return type, as mentioned use Func and make the return type the last type parameter (Func<string, int> is a function accepting a string and returning an int.)

More about delegates here.

Using an interface

public interface IObjectWithX
{
  void X();
}

public class MyObjectWithX : IObjectWithX
{
  public void X()
  {
    // do something
  }
}

public class ActionClass
{
  public static void DoWork(IObjectWithX handlerObject)
  {
    // do work
    handlerObject.X();
  }
}

public static void Main()
{
  var obj = new MyObjectWithX()
  ActionClass.DoWork(obj);
}
like image 152
bendewey Avatar answered Nov 13 '22 13:11

bendewey


Sounds like a perfect recipe for delegates - in particular, callbacks with delegates are exactly how this is handled in the asynchronous pattern in .NET.

The caller would usually pass you some state and a delegate, and you store both of them in whatever context you've got, then call the delegate passing it the state and whatever result you might have.

You could either make the state just object or potentially use a generic delegate and take state of the appropriate type, e.g.

public delegate void Callback<T>(T state, OperationResult result)

Then:

public void DoSomeOperation(int otherParameterForWhateverReason,
                            Callback<T> callback, T state)

As you're using .NET 3.5 you might want to use the existing Func<...> and Action<...> delegate types, but you may find it makes it clearer to declare your own. (The name may make it clearer what you're using it for.)

like image 44
Jon Skeet Avatar answered Nov 13 '22 15:11

Jon Skeet