2
\$\begingroup\$

I'm currently working on a system using WCF to communicate between a Windows Service and one or multiple clients. Service is required to answer clients calls, as well as notify them of certain events, which is why I implemented a callback feature using simplified subscriber model. Callback interface has methods with various signatures and I'd like to use a single method to invoke one of them for all subscribers (placing enumerating over them and exception handling in one place). At first I tried approach with an enum containing interface methods and a switch statement to invoke particular method.

private enum CallbackFunc { Method1, Method2, Method3 }
private static void InvokeCallback(CallbackFunc callbackFunc, params object[] args)
{
    foreach (var subscriber in subscribers)
    {
        try
        {
            switch (callbackFunc)
            {
                case CallbackFunc.Method1:
                    subscriber.Method1((int)args[0]);
                    break;
                case CallbackFunc.Method2:
                    Foo foo = args[0] as Foo;
                    if (foo != null)
                        subscriber.Method2(foo , args.Length > 1 ? args[1] as List<Bar> : null);
                    break;
                case CallbackFunc.Method3:
                    subscriber.Method3((Bar)args[0], (Baz)args[1]);
                    break;
            }
        }
        catch
        {
            //error handling
        }
    }
}

This solution works, but I don't like it very much... it's missing finesse. I figured I could do it more universally using delegates, at which I failed because of different method signatures. Next step was to use reflection with the following result:

private static void InvokeCallback(System.Reflection.MethodInfo func, params object[] args)
{
    foreach (var subscriber in subscribers)
    {
        try
        {
            func.Invoke(subscriber, args);
        }
        catch
        {
            //error handling
        }
    }
}

As you can see the code is much nicer, but I began to doubt if this is actually a better solution (for example because of a little reflection overhead, less nice function call).

public static void Method1(int a)
{
    InvokeCallback(typeof(ICallback).GetMethod("Method1"), a);
    InvokeCallback(CallbackFunc.Method1, a);
}
public static void Method2(Foo foo, List<Bar> bars)
{
    InvokeCallback(typeof(ICallback).GetMethod("Method2"), foo, bars);
    InvokeCallback(CallbackFunc.Method2, foo, bars);
}
public static void Method3(Bar bar, Baz baz)
{
    InvokeCallback(typeof(ICallback).GetMethod("Method3"), bar, baz);
    InvokeCallback(CallbackFunc.Method3, bar, baz);
}

I'd like to ask you which of these approaches is better or suggest a better solution. Any help will be much appreciated, thanks in advance.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Why not expose a lambda expression like this (assuming that _subscribers is a field of type List<ICallback>):

private void InvokeCallbacks(Action<ICallback> callbackFunc)
{
    _subscribers.ForEach(callbackFunc);
}

and usage would be:

public void Method1(int a)
{
    InvokeCallbacks(callback => callback.Method1(a));
}

public void Method2(Foo foo, List<Bar> bars)
{
    InvokeCallbacks(callback => callback.Method2(foo, bars));
}

public void Method3(Bar bar, Baz baz)
{
    InvokeCallbacks(callback => callback.Method3(bar, baz));
}
\$\endgroup\$
1
  • \$\begingroup\$ Perfect! This is exactly what I was looking for. Thank you :-) \$\endgroup\$
    – slawekwin
    Commented Feb 21, 2013 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.