I'm trying to make a design for some sort of IExecutable interface. I will not get into details, but the point is that I have several Actions that need to be executed from a base class. They may take different parameters (no big deal), and they may/may not return a value.
So far, this is my design:
public abstract class ActionBase
{
// ... snip ...
}
public abstract class ActionWithResultBase<T>: ActionBase
{
public abstract T Execute();
}
public abstract class ActionWithoutResultBase: ActionBase
{
public abstract void Execute();
}
So far, each of my concrete actions need to be a child from either ActionWithResultBase or ActionWithoutResult base, but I really don't like that. If I could move the definition of Execute to ActionBase, considering that the concrete class may or may not return a value, I will have achieved my goal.
Someone told me this could be done with using Func and Action, for which I totally agree, but I can't find a way to have that into one single class so that the caller would know if the action is going to return a value or not.
Brief: I want to do something like:
// Action1.Execute() returns something.
var a = new Action1();
var result = a.Execute();
// Action2.Execute() returns nothing.
var b = new Action2();
b.Execute();
Actions can only take input parameters, while Funcs can take input and output parameters. It is the biggest difference between them. An action can not return a value, while a func should return a value in the other words.
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. It can contain minimum 1 and maximum of 16 input parameters and does not contain any output parameter.
Func is a delegate that points to a method that accepts one or more arguments and returns a value. Action is a delegate that points to a method which in turn accepts one or more arguments but returns no value. In other words, you should use Action when your delegate points to a method that returns void.
Action<T> Delegate (System)Encapsulates a method that has a single parameter and does not return a value.
If you want a lightweight solution, then the easiest option would be to write two concrete classes. One will contain a property of type Action
and the other a property of type Func<T>
:
public class ActionWithResult<T> : ActionBase {
public Func<T> Action { get; set; }
}
public class ActionWithoutResult : ActionBase {
public Action Action { get; set; }
}
Then you can construct the two types like this:
var a1 = new ActionWithResult<int> {
CanExecute = true,
Action = () => {
Console.WriteLine("hello!");
return 10;
}
}
If you don't want to make Action
property read/write, then you could pass the action delegate as an argument to the constructor and make the property readonly.
The fact that C# needs two different delegates to represent functions and actions is quite annoying. One workaround that people use is to define a type Unit
that represents "no return value" and use it instead of void
. Then your type would be just Func<T>
and you could use Func<Unit>
instead of Action
. The Unit
type could look like this:
public class Unit {
public static Unit Value { get { return null; } }
}
To create a Func<Unit>
value, you'll write:
Func<Unit> f = () => { /* ... */ return Unit.Value; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With