Action.` This is a 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 `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. `Lambdas `lambda`Start.` The Actions point to anonymous functions. These functions cannot return values onto the evaluation stack. An Action instance can receive parameters, but cannot return values. `Return `return`So: `An Action instance is similar to a void method. The program shows how to Invoke the Action instances.`Notes, above program.` We use Action with 3 lambda expressions. The first Action instance uses the constructed type Action<int>, and an explicit parameter list in the lambda expression. `It receives one argument when invoked. It returns no result—it is a void delegate method.`Notes, continued.` The second and third Action instances also return no value. The second Action receives 2 int parameters. The third Action receives no parameters. `Int `int`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 Method `generic-method`This information is determined at compile-time, before runtime. If a program compiles, it uses the correct argument types.`A benchmark.` How much slower are delegate method calls than direct method calls? To test this, we use the Action type with a single parameter. `Overview: `This program introduces the Method1 method, which contains some dummy code for testing.`First: `In the first loop, Method1 (which uses no Action) is called directly 100 million times.`Second: `In the second loop, an Action instance that points to Method1 is invoked the same number of times.`Notes, above benchmark.` For a method with one parameter and no return value, the Action invocation costs more than 3 ns extra each time. This is unlikely to cause many performance problems.`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 `func`Abstract.` Next, we compare abstract methods. An Action<int> can be an instance that points to any function that receives an int parameter. `However: `You can design an abstract class with an abstract method that also can be used in this way.`Abstract `abstract`Next: `In the following program, we test such an abstract class against an Action<int>.`Benchmark `benchmark`Results, above benchmark.` The Action was slower to call than the method from the abstract class reference. If you can use abstract classes instead of Actions, this will be faster.`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 `dictionary`In this example, we invoke two static void methods based on simple string keys.`Static Method `static`Idea: `You could use a Dictionary of an abstract class. Then, instantiate each method as an instance of a derived class.`Inheritance `inheritance`A summary.` Programs use Action for many purposes. The Action type specifies a function object that can receive parameters, but never returns a value onto the stack. `Thanks to Turker Tunali for helping clarify the Action descriptive text. All contributions are appreciated.`Void methods.` Action instances are void methods. As higher-order procedures, they can be passed around as objects. This is powerful.

UVX VPVOVSVDV; { UV$U{X UUV{EVQ Action instances. UUV2First eVQ uses one parameter. UUV2Second eVQ uses two parameters. UUV2Third eVQ uses no parameter. UUV2None have VIs. UUXActionX<V}> eVQ1 =V'(Vsx) => V%X"Vh {0}"X, x); UUXActionX<V}, V}> eVQ2 =V'(x, y) => V%X"Vh {0}VR{1}"X, x, y); UUXActionX eVQ3 =V'() => V%X"Done"X);X UUV{Call the anonymous mV[s. UUXeVQ1.Invoke(1); UUeVQ2.Invoke(2, 3); UUeVQ3.Invoke(); U} } X Vh 1 Vh 2VR3 DoneX VPVO; V! VDV; { Uconst Vs_maxVz100000000; UV$U{X UUV{CV` Action delegate VoMV[1. UUXAction<V}> actionVzVwAction<V}>(MV[1)VSUUvar s1VzV-.VcNew(); UUVo(VsiVz0; i < _max; i++) UU{XV'V{Direct call.V'XMV[1(5); UU} UUs1V1; UUvar s2VzV-.VcNew(); UUVo(VsiVz0; i < _max; i++) UU{XV'V{Delegate call.V'Xaction.Invoke(5); UU} UUs2V1; UUV%(V.(s1.V" * 1000 * 1000) /V'_max).ToVM("0.00 ns")); UUV%(V.(s2.V" * 1000 * 1000) /V'_max).ToVM("0.00 ns")); UUV4.Vx(); U} UVAVfMV[1(Vsparam) U{X UUV{Dummy. UUXVrparamVi-1) UU{V'throw VwV)(); UU} U} } X X0.32 ns 3.52 nsX VPVO; V! abstract VDA { UV=abstract VfMV[A(Vsy); } VDAB : A { UV=override VfMV[A(Vsy) U{ U} } VDV; { UVAVfMV[A(Vsy) U{ U} UV$U{ UUA abstVzVwAB(); UUabst.MV[A(0)VSUUAction<V}> actionVzVwAction<V}>(MV[A); UUaction.Invoke(0)VSUUconst VsmaxVz100000000; UUvar s1VzV-.VcNew(); UUVo(VsiVz0; i < max; i++) UU{V'abst.MV[A(i);V'abst.MV[A(i); UU} UUs1V1; UUvar s2VzV-.VcNew(); UUVo(VsiVz0; i < max; i++) UU{V'action.Invoke(i);V'action.Invoke(i); UU} UUs2V1; UUV%(V.(s1.V" * 1000000) /V'max).ToVM("0.00 ns")); UUV%(V.(s2.V" * 1000000) /V'max).ToVM("0.00 ns")); UUV4.Vx(); U} } X X3.54 ns 6.68 nsX VPVO; V VDV; { UV$U{ UUDV+<VL, Action> dictVzVwDV+<VL, Action>(); UUdict["cat"]VzVwAction(Cat); UUdict["dog"]VzVwAction(Dog)VSUUdict["cat"].Invoke(); UUdict["dog"].Invoke(); U} UVAVfCat() U{ UUV%X"CAT"X); U} UVAVfDog() U{ UUV%X"DOG"X); U} } X CAT DOGX

fAction type and Invoke7tests Action invocation3benchmarks abstractfDictionary with Action