Home
C#
Action Type
Updated May 11, 2023
Dot Net Perls
Action. This is a C# function object. Action objects return no values. The Action type is similar to a void method—this generic type is found in the System namespace.
void
To specify an Action, we must have no return value. The Action must never return a value onto the evaluation stack. Often we use lambdas to specify Actions.
Lambda
First example. These Actions point to anonymous functions. These functions cannot return values. An Action instance can receive parameters, but cannot return values.
return
Version 1 This Action receives one int argument when invoked. It returns no result—it is a void delegate method.
int
Version 2 This Action receives 2 arguments, named "x" and "y." It prints them out to the console.
Version 3 This Action receives no parameters. So we have a method that receives no arguments, and returns no values.
using System; // Version 1: this Action uses one parameter. Action<int> example1 = (int x) => Console.WriteLine("Write {0}", x); example1.Invoke(1); // Version 2: second example uses 2 parameters. Action<int, int> example2 = (x, y) => Console.WriteLine("Write {0} and {1}", x, y); example2.Invoke(2, 3); // Version 3: third example uses no parameter. Action example3 = () => Console.WriteLine("Done"); example3.Invoke();
Write 1 Write 2 and 3 Done
Benchmark, methods. How much slower are delegate method calls than direct method calls? To test this, we use the Action type with a single parameter.
Version 1 In the first loop, Method1 (which uses no Action) is called directly 100 million times.
Version 2 In the second loop, an Action instance that points to Method1 is invoked the same number of times.
Result For a method with 1 parameter and no return value, the Action invocation costs more than 3 ns extra each time.
using System; using System.Diagnostics; class Program { const int _max = 100000000; static void Main() { // Create Action delegate for Method1. Action<int> action = new Action<int>(Method1); var s1 = Stopwatch.StartNew(); // Version 1: use direct call. for (int i = 0; i < _max; i++) { Method1(5); } s1.Stop(); var s2 = Stopwatch.StartNew(); // Version 2: use Action (delegate) call. for (int i = 0; i < _max; i++) { action.Invoke(5); } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) / _max).ToString("0.00 ns")); } static void Method1(int param) { // Dummy. if (param == -1) { throw new Exception(); } } }
0.32 ns Direct call 3.52 ns Action Invoke call
Benchmark, abstract. Next we benchmark abstract methods. An Action int can be an instance that points to any function that receives an int parameter.
Version 1 In this version of the code, we test an abstract class. We repeatedly call a method on it.
abstract
Benchmark
Version 2 Here we call a method on an Action instance. The code performs the same number of method calls as version 1.
Result The Action was slower to call than the method from the abstract class reference.
using System; using System.Diagnostics; abstract class A { public abstract void MethodA(int y); } class AB : A { public override void MethodA(int y) { } } class Program { static void MethodA(int y) { } static void Main() { A abst = new AB(); abst.MethodA(0); Action<int> action = new Action<int>(MethodA); action.Invoke(0); const int max = 100000000; var s1 = Stopwatch.StartNew(); // Version 1: use abstract class method. for (int i = 0; i < max; i++) { abst.MethodA(i); abst.MethodA(i); } s1.Stop(); var s2 = Stopwatch.StartNew(); // Version 2: use Action. for (int i = 0; i < max; i++) { action.Invoke(i); action.Invoke(i); } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / max).ToString("0.00 ns")); } }
3.54 ns Abstract call 6.68 ns Action Invoke() call
Dictionary. It is possible to use Action as the value in a Dictionary instance. This makes it possible to call functions by a string key.
Dictionary
Here In this example, we invoke two static void methods based on simple string keys.
static
Tip You could use a Dictionary of an abstract class. Then, instantiate each method as an instance of a derived class.
using System; using System.Collections.Generic; class Program { static void Main() { Dictionary<string, Action> dict = new Dictionary<string, Action>(); dict["cat"] = new Action(Cat); dict["dog"] = new Action(Dog); dict["cat"].Invoke(); dict["dog"].Invoke(); } static void Cat() { Console.WriteLine("CAT"); } static void Dog() { Console.WriteLine("DOG"); } }
CAT DOG
Notes, Invoke. The Invoke method receives a number of arguments equal to the specific type of Action. We must specify these arguments in the Action type declaration.
Generic
Tip This information is determined at compile-time, before runtime. If a program compiles, it uses the correct argument types.
Funcs. What is the difference between Action and Func? The Action type receives parameters but does not return a parameter. Func receives parameters and returns a result value.
So An Action instance never returns anything, while the Func always returns something.
Func
Programs use Actions for many purposes. The Action type specifies a function object that can receive parameters, but never returns a value onto the stack.
Dot Net Perls is a collection of pages with code examples, which are updated to stay current. Programming is an art, and it can be learned from examples.
Donate to this site to help offset the costs of running the server. Sites like this will cease to exist if there is no financial support for them.
Sam Allen is passionate about computer languages, and he maintains 100% of the material available on this website. He hopes it makes the world a nicer place.
This page was last updated on May 11, 2023 (simplify).
Home
Changes
© 2007-2025 Sam Allen