Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use func method for an action also?

Tags:

c#

action

func

I created a method to abstract try/catch functionality. I have about 30 methods that have this exact same try/catch scenario. So I put it in one method:

    private T Invoke<T>(Func<T> func)
    {
        try
        {
            return func.Invoke();
        }
        catch (Exception ex)
        {
            throw LogAndThrowFaultException(ex);
        }
    }

Now, most of the methods call it like this:

    public IEnumerable<PingResponse> GetAllForPingRequest(PingRequest pingRequest)
    {
        return Invoke(() => PingResponseLogic.GetAllForPingRequest(pingRequest));
    }

My issue is that I have just a couple of methods that call it without needing to return a value:

Invoke<void>(() => CustomVariableGroupLogic.Delete(customVariableGroup));

However, I can't use void there. The Invoke() method takes a func, but in this case it needs to be an action. I did some research and it looks like I may have to create another Invoke() method, but have it take an action. Those suggestions were from 2009 and 2010 though. Is it possible to somehow use my func method without having to create another Invoke() method like Invoke2()?

like image 907
Bob Horn Avatar asked Jun 04 '13 19:06

Bob Horn


3 Answers

One quick and dirty solution would be to add default value after calling Delete method. It will be ignored anyway, if you don't assign result of the Invoke method to a variable. For instance, next code demonstrates this:

Invoke(() => {CustomVariableGroupLogic.Delete(customVariableGroup); return 0; });

You can see similar example proposed here,

If you have lots and lots of such calls, you can build a fancy wrapper, that will return Func for a given Action. Example:

Func<Action, Func<int>> wrap = action => () => {action(); return 0;};

now you can

Invoke(() => wrap(() => CustomVariableGroupLogic.Delete(customVariableGroup)));

but this goes a little bit close to lambda craziness

Inspired by pcm2:

you can create an overload to Invoke, that simply takes Action as a parameter, use solution proposed above to call implementation with Func<T>:

public void Invoke(Action action)
{
    Invoke(() => {action(); return 0;});
}

now you simply can

Invoke(() => CustomVariableGroupLogic.Delete(customVariableGroup));
like image 117
Ilya Ivanov Avatar answered Oct 13 '22 01:10

Ilya Ivanov


Could you not just create an overload of invoke?

public void Invoke<T>(Func<T> func){
    return (T) InvokeInternal(func);
}

public void Invoke(Action action){
    InvokeInternal(action);
}

If you'd then want both methods to do the exact same thing, and keeping things DRY, you could create a method like so:

private object InvokeInternal(System.Delegate @delegate)
{
    try
    {
        return @delegate.DynamicInvoke();
    }
    catch (Exception ex)
    {
        throw LogAndThrowFaultException(ex);
    }
}

And have both your overloads calling this method, appropriately casting the result, if any

like image 42
Christoffer Mansfield Avatar answered Oct 13 '22 00:10

Christoffer Mansfield


  1. Do you really have to func.Invoke()? Why not just func()?
  2. Why isn't your Invoke static?
  3. Depending on what LogAndThrowFaultException is doing, this could be pretty bad. Make sure that the exception stack is preserved by always setting the inner exception to ex.

But yes, you need a second function that returns void instead of T.

like image 32
Reinderien Avatar answered Oct 12 '22 23:10

Reinderien