Вопрос

Я пытаюсь сделать дизайн для своего рода IExecutable интерфейса. Я не буду вспоминаться, но точка в том, что у меня есть несколько действий, которые необходимо выполнить из базового класса. Они могут принимать разные параметры (нет большого значения), и они могут / могут не вернуть значение.

До сих пор это мой дизайн:

public abstract class ActionBase
{
    // ... snip ...
}

public abstract class ActionWithResultBase<T>: ActionBase
{
    public abstract T Execute();
}

public abstract class ActionWithoutResultBase: ActionBase
{
    public abstract void Execute();
}

До сих пор каждая из моих конкретных действий должна быть ребенком из-за базы DoachWithResultBase или ActionWithoutResult, но мне это действительно не нравится. Если бы я мог переместить определение Execute для ActionBase, учитывая, что конкретный класс может или не может вернуть ценность, я достигнут моей цели.

Кто-то сказал мне, что это может быть сделано с помощью функций и действий, для которых я полностью согласен, но я не могу найти способ иметь это в одном классе, чтобы абонент был бы, если действие будет возвращать значение или нет.

Краткое: я хочу сделать что-то вроде:

// Action1.Execute() returns something.
var a = new Action1();
var result = a.Execute();

// Action2.Execute() returns nothing.
var b = new Action2();
b.Execute();
Это было полезно?

Решение

Если вы хотите легкое решение, то самый простой вариант будет написать два бетонных класса. Один будет содержать свойство типа Action а другое свойство типа Func<T>:

public class ActionWithResult<T> : ActionBase { 
  public Func<T> Action { get; set; } 
}

public class ActionWithoutResult : ActionBase {
  public Action Action { get; set; }
}

Тогда вы можете построить два типа, как это:

var a1 = new ActionWithResult<int> { 
  CanExecute = true,
  Action = () => { 
    Console.WriteLine("hello!");
    return 10; 
  }
}

Если вы не хотите делать Action Свойство чтение / запись, то вы можете передать делегат действий в качестве аргумента конструктора и сделать свойство Readonly.

Тот факт, что C # нуждается в двух разных делегатах для представления функций, а действия довольно раздражают. Один обходной путь, которые используют люди, состоит в том, чтобы определить тип Unit который представляет собой «без возврата» и использовать его вместо void. Отказ Тогда ваш тип будет просто Func<T> и вы могли бы использовать Func<Unit> вместо Action. Отказ То Unit Тип может выглядеть так:

public class Unit {
  public static Unit Value { get { return null; } }
}

Создать а Func<Unit> Значение, вы напишите:

Func<Unit> f = () => { /* ... */ return Unit.Value; }

Другие советы

Следующие интерфейсы должны сделать трюк - это по сути, копирование оттудаваемого шаблона

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() { //... }
}

Вы знаете, что вы можете игнорировать возвращаемое значение метода правильно? Вы не имеют использовать его.

Как насчет чего-то простого:

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

    public object Execute(params object[] p)
    {
        return del.DynamicInvoke(p);
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top