12

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();
Alpha
  • 7,586
  • 8
  • 59
  • 92
  • As a clarification: my goal is to have an abstract Execute in ActionBase and avoid creating ActionWithResultBase and ActionWithoutResultBase. – Alpha Nov 25 '10 at 17:04

4 Answers4

11

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; }
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Thank you. I know I waited long before marking your answer, but I really wanted to see if someone came up with a solution. Even when your approach does not quite solve the problem, it is indeed a good answer, and shows a good and nice workaround on how to overcome this problem. – Alpha May 30 '11 at 21:24
2

The following interfaces should do the trick -- it's essentially copying the Nullable pattern

public interface IActionBase
{
       bool HasResult { get; }
       void Execute() { }
       object Result { get; }
}

public interface IActionBase<T> : IActionBase
{
       new T Result { get; }
}

public sealed class ActionWithReturnValue<T> : IActionBase<T>
{
       public ActionWithReturnValue(Func<T> action) {  _action = action; }
       private Func<T> _action;

       public bool HasResult { get; private set; }
       object IActionBase.Result { get { return this.Result; } }
       public T Result { get; private set; }
       public void Execute()
       {
            HasResult = false;
            Result = default(T);
            try 
            { 
                 Result = _action();
                 HasResult = true;
             }
            catch
            {
                HasResult = false;
                Result = default(T);   
            }  
       }

}

public sealed class ActionWithoutReturnValue : IActionBase
{
      public bool HasResult { get { return false; } }
      object IActionBase.Result { get { return null; } }
      public void Execute() { //... }
}
cordialgerm
  • 8,403
  • 5
  • 31
  • 47
0

You know that you can ignore the return value of a method right? You don't have to use it.

annakata
  • 74,572
  • 17
  • 113
  • 180
  • Yes, you are correct on that, but I don't think that would be something design-wise to have. Also, someone suggested me to return always bool for those no-returns that would just indicate that the operation was successful, but I also think that's not correct. If the operation should not return a value, why force it? – Alpha Nov 25 '10 at 16:48
  • @Alpha - I agree with you that if an operation doesn't naturally return something it shouldn't. Returning "true" isn't right because egnerally you shouldn't return "false" you should throw an exception. However I still don't understand your design goal - your objective seems to be based on syntactic sugar and I don't see what you're accomplishing that you couldn't just get Action and Func to solve. I think you need to explain what's the problem with them? – annakata Nov 25 '10 at 16:52
0

what about something simple:

public class ActionExecuter
{
    private MulticastDelegate del;
    public ActionExecuter(MulticastDelegate del)
    {
        this.del = del;
    }

    public object Execute(params object[] p)
    {
        return del.DynamicInvoke(p);
    }
}
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
  • Also thought about something similar, but my problem is that I won't know at compile time which type is returned. I could always make ActionExecuter and make Execute return T, but that beats situations were I need not to return anything. – Alpha Nov 25 '10 at 17:09