Encapsulating Action and Func?

前端 未结 4 1439
栀梦
栀梦 2021-02-08 09:46

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 ba

相关标签:
4条回答
  • 2021-02-08 09:54

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

    0 讨论(0)
  • 2021-02-08 09:56

    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() { //... }
    }
    
    0 讨论(0)
  • 2021-02-08 10:00

    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);
        }
    }
    
    0 讨论(0)
  • 2021-02-08 10:05

    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; }
    
    0 讨论(0)
提交回复
热议问题