Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Action<T> as an argument in C# (mimicking a function pointer)

Tags:

c#

delegates

I need to write a delegate function that can 'wrap' some while/try/catch code around a basic UDP call to verify the link. I made it work for Func for a function that has no arguments, but I can't make it work for Action, which has an argument (but no return). I can't seem to pass in the argument in a logical way without the compiler complaining.

Am I going about this all wrong? I'm new to C# and I'm essentially trying to mimick the idea of a function pointer. Should I not be overloading this function? I know you can't overload delegates (I assume that's why Func and Action exist).

This works:

protected TResult udpCommand<TResult>(Func<TResult> command)
        {
            TResult retValue = default(TResult);
            while (!linkDownFail)
            {
                try
                {
                    retValue = command();
                    break;
                }
                catch
                {
                    LinkStateCallBack(ip, getLinkStatus());
                    if (linkDownFail) throw new LinkDownException();
                    Thread.Sleep(100);
                }
            }
            return retValue;
        }

But this does not:

protected void udpCommand<T>(Action<T> command(T value))
        {
            while(!linkDownFail)
            {
                try
                {
                    command(value);
                    break;
                }
                catch
                {
                    LinkStateCallBack(ip, getLinkStatus());
                    if (linkDownFail) throw new LinkDownException();
                    Thread.Sleep(100);
                }
            }
            return;
        }

Calling convention (for one that works):

udpCommand<uint>(someUdpCommand);
like image 939
cgyDeveloper Avatar asked Jun 30 '09 20:06

cgyDeveloper


People also ask

What is action t used for in an application?

You can use the Action<T> delegate to pass a method as a parameter without explicitly declaring a custom delegate. The encapsulated method must correspond to the method signature that is defined by this delegate.

How do you pass an action to a method?

Use Action Delegate to Pass a Method as a Parameter in C# We can also use the built-in delegate Action to pass a method as a parameter. The correct syntax to use this delegate is as follows. Copy public delegate void Action<in T>(T obj); The built-in delegate Action can have 16 parameters as input.

What is Action <> C#?

Action is a delegate type defined in the System namespace. An Action type delegate is the same as Func delegate except that the Action delegate doesn't return a value. In other words, an Action delegate can be used with a method that has a void return type. For example, the following delegate prints an int value.

What can you use to pass parameters to actions?

You can pass them via a URL, a query string, a request header, a request body, or even a form.


3 Answers

If you want this to be generic enough to handle any number of arguments, try using the non-genernic Action delegate:

protected void udpCommand(Action command)
{
    while(!linkDownFail)
    {
        try
        {
            command();
            break;
        }
        catch
        {
            LinkStateCallBack(ip, getLinkStatus());
            if (linkDownFail) throw new LinkDownException();
            Thread.Sleep(100);
        }
    }
    return;
}

In C# 3.0, you can call it like this:

udpCommand(() => noParameterMethod());
udpCommand(() => singleParameterMethod(value));
udpCommand(() => manyParameterMethod(value, value2, value3, value4));

In C# 2.0 it's a little uglier:

udpCommand(delegate { noParameterMethod(); });
udpCommand(delegate { singleParameterMethod(value); });
udpCommand(delegate { manyParameterMethod(value, value2, value3, value4); });

This gives you deferred execution without locking you into a particular method signature.

EDIT

I just notice I kinda stole Marc Gravell's comment... apologies Marc. To answer how you might reduce your duplication, you can have the Action method call the Func<T> method, like this:

protected void udpCommand(Action command)
{
    udpCommand(() => { command(); return 0; });
}

I believe (and I may be wrong) that returning 0 is no more costly than (implicitly) returning void, but I may be way off here. Even it it does have a cost, it would only put a tiny itty bitty snoodge extra on the stack. In most cases, the additional cost won't ever cause you any grief.

like image 63
Michael Meadows Avatar answered Nov 09 '22 10:11

Michael Meadows


Do you mean:

    protected void udpCommand<T>(Action<T> command, T value) {...}

With calling:

udpCommand(someUdpCommand, arg);

Note that this may work better on C# 3.0, which has stronger generic type inference than C# 2.0.

like image 32
Marc Gravell Avatar answered Nov 09 '22 10:11

Marc Gravell


I think you just need to take out the (T value) after 'command'.

like image 32
Michael Bray Avatar answered Nov 09 '22 09:11

Michael Bray