Anonymous delegate as function parameter
Asked Answered
B

4

22

I'm trying to pass parameter, which is anonymous delegate (no input parameters, no return value), to function.

Something like this:

private function DoSomething(delegate cmd)
{
     cmd();
}

Then, I'm want to use this function to call function in this way:

DoSomething(delegate
{
     Console.WriteLine("Hooah!");
});

I'm want this specific way, because it's easy to use writing style.

Possible?

Bini answered 15/2, 2014 at 9:38 Comment(2)
check msdn.microsoft.com/en-us/library/ms173172.aspx to see how delegates used as fucntion parameterRevet
possible duplicate of #3938856Revet
O
47

Exactly for such purposes Microsoft has created the Action and Func wrapper classes in the .NET framework. Both classes are relying on anonymous functions. Use Action if you don't need to return any result, just to execute the anonymous function:

private void DoSomething(Action action)
{
    action();
}

It can be used like this:

DoSomething(() => 
{
    Console.WriteLine("test");
});

The () => term is a lambda expression and means something like input with no parameters is calling .... See the documentation for a thorough explanation.

If you want to return a result, then use the Func delegate:

private T DoSomething<T>(Func<T> actionWithResult)
{
    return actionWithResult();
}

Usage:

Console.WriteLine(DoSomething<int>(() => 
{
    return 100;
}));

Both wrappers have overrides that accept up to 8 parameters.

When using Func, the last parameter is always the return type:

// returns a string
Func<string> t = () => { return "test string"; };
// first parameter is of type int, result of type string
Func<int, string> toString = (id) => { return id.ToString(); };
// parameters are of type int and float, result is string
Func<int, float, string> sumToString = (n1, n2) => { return (n1 + n2).ToString(); };

The Func wrapper can be used directly with a typed parameter:

Func<string, string> up = text => text.ToUpper();
Console.WriteLine(up("test"));

I often use Func's in order to create a generic executor that is wrapped in a try/catch block and logging if something happens. This way i reduce the repetative code:

private T safeCallWithLog<T>(Func<T> action)
{
    try
    {           
        return action();
    }
    catch (Exception ex)
    {
        Console.WriteLine(String.Format("Oops ...: {0}", ex.Message));
    }
    // return default type if an error occured
    return default(T);
}

Usage:

var result = safeCallWithLog<DbEntry>(() =>
            {
                return databaseContext.GetEntryWithId(42);
            });

var id = safeCallWithLog<int>(() =>
                    {
                        return databaseContext.GetIdFor("J.D.");
                    }); 

You could still use the original delegate concept. The Action and the Func classes are just wrappers around predefined generic delegate methods.

// declare delegate contract
private delegate void output();
// create caller method
private void method(output fun)
{
    fun();
}
// some test functions, that must match exactly the delegate description
// return type and number of arguments
private void test1()
{
    Console.WriteLine("1");
}

private void test2()
{
    Console.WriteLine(DateTime.Now.ToString());
}

// call different methods
method(test1);
method(test2);
// inline call without hard coded method
method(delegate() 
{
    Console.WriteLine("inline");
});
Octagonal answered 15/2, 2014 at 9:41 Comment(0)
S
3

.NET has a bunch of these built in. Action is the one you want for no parameters and no return types:

private function DoSomething(Action cmd)
{
    cmd();
}

There's also a generic version(s) of Action if you want a delegate with parameters but no return types (e.g. Action<int, int> for a method that takes two ints and has no return).

Func and Predicate (along with generic versions for those too) also exist.

Spherics answered 15/2, 2014 at 9:41 Comment(0)
F
1

However Pasty describe most possible solvings, I just want to add about the key word delegate.

  • The first case is - to declare new type:

In the example it is used to describe an input parameter

private function DoSomething(delegate cmd)
{ 
     cmd();
}

But it can be used to declare object type that is used to contain a pointer to function:

public delegate *returnParameterType* NewTypeName(*inputParamType1* inputParam1, ...)

and then used that NewTypeName as a type for input parameter:

private function DoSomething(NewTypeName cmd)
    { 
         cmd();  
    }
  • The second case of usinf key word 'delegate' is like in your example - to declare anonymous method

    delegate() { Console.WriteLine("Hooah!"); }


However at that situation such method must be assigned or to suitable defined delegate either to generic delegate like Action, because Action isn't supposed to have output parameters

private void delegate Output();
Output func = delegate(){Console.WriteLine("Hooah!");}

or

Action func1 = delegate(){Console.WriteLine("Hooah!");}
Fountain answered 21/3, 2016 at 14:29 Comment(0)
C
0

Sure it's possible. For method without a return type use Action otherwise Func<>.

public void Function(Action action)
{
    action();
}

and call it like

Function(() => System.Console.WriteLine("test"));

It's even more pleasant way using lambdas instead of the delegate keyword. You can even execute the action using action.Invoke(), but in my opinion it's better to call it like it's a method, which it is actually.

Closemouthed answered 15/2, 2014 at 9:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.