C#Building Fluent API用于方法调用

Roo*_*ian 7 c# fluent-interface

我该怎么做才能说InvokeMethod可以调用一个方法,当使用像Repeat这样的特殊选项时,它应该在Repeat之后执行.

我现在的问题是该方法在知道必须被调用100次之前就已经执行了.

class Program
{
    static void Main()
    {
        const bool shouldRun = true;

        new MethodExecuter()
            .ForAllInvocationsUseCondition(!Context.WannaShutDown)
                .InvokeMethod(A.Process).Repeat(100)
                .When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
            .ForAllInvocationsUseCondition(Context.WannaShutDown)
                .When(shouldRun).ThenInvokeMethod(C.Process);
    }
}
Run Code Online (Sandbox Code Playgroud)

MethodExpression的

public class MethodExpression
{
    private bool _isTrue = true;
    private readonly MethodExecuter _methodExecuter;
    public MethodExpression(bool isTrue, MethodExecuter methodExecuter)
    {
        _isTrue = isTrue;
        _methodExecuter = methodExecuter;
    }

    public MethodExecuter ThenInvokeMethod(Action action)
    {
        if (_isTrue)
        {
            action.Invoke();
            _isTrue = false;
        }
        return _methodExecuter;
    }
}
Run Code Online (Sandbox Code Playgroud)

MethodExecuter

public class MethodExecuter
{
    private bool _condition;
    private int _repeat = 1;

    public MethodExpression When(bool isTrue)
    {
        return new MethodExpression(isTrue && _condition, this);
    }

    public MethodExecuter InvokeMethod(Action action)
    {
        if (_condition)
        {
            for (int i = 1; i <= _repeat; i++)
            {
                action.Invoke();
            }
        }
        return this;
    }

    public MethodExecuter ForAllInvocationsUseCondition(bool condition)
    {
        _condition = condition;
        return this;
    }

    public MethodExecuter Repeat(int repeat)
    {
        _repeat = repeat;
        return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

Jay*_*Jay 2

有很多方法可以给这只猫剥皮,但我认为这种困难的一个根源在于您实际上在方法中调用了该方法InvokeMethod()(想想看!)。

通常,我们使用流畅的 API 将从内到外评估的语法转换为可以以从左到右的方式表达的语法。因此,接口的表达式构建器组件用于在整个表达式中构建状态,并且只有在最后才会发生“真正的工作”。

解决当前问题的一种解决方案是将每个操作及其关联选项(调用条件、重复计数等)排队,并添加一些ExecuteAll()方法以MethodExecuter在成员链末尾出队并执行完全配置的操作。

另一种解决方案是将所有执行选项放在InvokeMethod()方法内;就像是:

.Invoke(x => x.Method(A.Process).Repeat(100))
Run Code Online (Sandbox Code Playgroud)

这个方法看起来像:

public MethodExecuter Invoke(Action<IExecutionBuilder> executionBuilder)
 {
     var builder = new ExecutionBuilder();
      executionBuilder(builder);

      var action = builder.Action; 
      var repeat = builder.RepeatCount;

      if (_condition)
      {
          for (int i = 1; i <= repeat; i++)
            {
                action();
            }
      }

      return this;
 }
Run Code Online (Sandbox Code Playgroud)

我还没有在 Visual Studio 中完成此操作,但其他项目类似于:

public interface IExecutionBuilder
 {
     IExecutionBuilder Method(Action action);
      IExecutionBuilder Repeat(int count);
 }

 public class ExecutionBuilder : IExecutionBuilder
 {
      public ExecutionBuilder()
      {
          RepeatCount = 1; // default to repeat once
            Action = () => {}; // default to do nothing, but not null
      }

     public IExecutionBuilder Method(Action action)
      {
          Action = action;
          return this;
      }

      public IExecutionBuilder Repeat(int repeat)
      {
          RepeatCount = repeat;
                  return this;
      }

      public int RepeatCount { get; private set; }
      public Action Action { get; private set; }
 }
Run Code Online (Sandbox Code Playgroud)

请注意,RepeatCountAction没有暴露在界面上。这样,您在调用时将看不到这些成员,但在方法内.Invoke(x => x.使用具体类时可以访问它们。ExecutionBuilderInvoke()