Bob Horn
Bob Horn

Reputation: 34297

Use func method for an action also?

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()?

Upvotes: 5

Views: 835

Answers (4)

Ilya Ivanov
Ilya Ivanov

Reputation: 23626

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));

Upvotes: 6

Shlomo
Shlomo

Reputation: 14350

You can wrap the action into a func like so. Or you can create a convenience function that does the wrapping:

void Main()
{
    Action<string> a = s => Console.WriteLine(s);

    Invoke(() => { a(); return null; });
    Invoke(s);
}

private void Invoke(Action a)
{
    Invoke(() => { a(); return null; };
}

Upvotes: 1

Christoffer Mansfield
Christoffer Mansfield

Reputation: 803

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

Upvotes: 2

Reinderien
Reinderien

Reputation: 15231

  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.

Upvotes: 1

Related Questions