C# 为方法调用构建 Fluent API
我必须做什么才能说 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);
}
}
方法表达式
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;
}
}
方法执行器
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;
}
}
What do I have to do to say that InvokeMethod can invoke a method and when using special options like Repeat it shall exexute after the Repeat.
My problem for now is that the method will already exexute before it knows that it has to be called 100 times.
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);
}
}
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;
}
}
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
使用最终方法(“go”或“execute”)来真正开始工作。
Use a final method ("go", or "execute") to actually kick things off.
您提供的内容看起来有点像对工作流程或状态机进行编程。为了在执行期间捕获调用并遵守条件,您需要稍微改变您的方法。
考虑将操作推入队列,然后提供运行状态机的机制,而不是在操作进入时调用操作。
What you've provided looks a bit like programming a workflow or state machine. In order to capture invocations and respect conditions during execution, you'd need to change your approach slightly.
Instead of invoking actions as they come in, consider pushing your actions into a queue and then providing an mechanism to run the state machine.
有很多方法可以给这只猫剥皮,但我认为这种困难的根源之一是您实际上在
InvokeMethod()
方法中调用了该方法(看图!)。通常,我们使用流畅的 API 将从内到外评估的语法转换为可以从左到右的方式表达的语法。因此,接口的表达式构建器组件用于在整个表达式中构建状态,并且只有在最后才会发生“真正的工作”。
解决当前问题的一种解决方案是将每个操作及其相关选项(调用条件、重复计数等)排队,并向
MethodExecuter
添加一些ExecuteAll()
方法在成员链末端出列并执行完全配置的操作。另一种解决方案是将所有执行选项放在
InvokeMethod()
方法中;类似于:此方法看起来类似于:
我还没有在 Visual Studio 中完成此操作,但其他项目类似于:
请注意,
RepeatCount
和Action
是不暴露在接口上。这样,您在调用.Invoke(x => x.
时将看不到这些成员,但在使用ExecutionBuilder
内的具体ExecutionBuilder
类时可以访问它们。代码>Invoke() 方法。There are a lot of ways to skin this cat, but I think one source of this difficulty is in the fact that you actually invoke the method within the
InvokeMethod()
method (go figure!).Typically, we use fluent APIs to turn syntax that is evaluated from the inside-out into something that can be expressed in a left-to-right fashion. Thus, the expression builder components of the interface are used to build up state throughout the expression, and only at the end does the "real work" happen.
One solution to your immediate problem is to queue up each action with its associated options (invocation conditions, repeat count, etc.), and add some
ExecuteAll()
method toMethodExecuter
that dequeues and executes the fully configured actions at the end of the member chain.Another solution would be to put all of the execution options inside the
InvokeMethod()
method; something like:This method would look something like:
I haven't worked through this in Visual Studio, but the other items would be something like:
Note that
RepeatCount
andAction
are not exposed on the interface. This way, you will not see these members when calling.Invoke(x => x.
, but will have access to them when using the concreteExecutionBuilder
class inside theInvoke()
method.您可以有一个
SetInvokeMethod
和一个Execute
方法。You could have a
SetInvokeMethod
and anExecute
Method.一句话,你的代码太“渴望”了。在流畅的语法结构告诉代码应该重复多少次之前,会调用 InvokeMethod 方法并执行操作。
要更改此设置,请尝试将要调用的方法指定为 methodInvoker 中的私有字段,然后包含一个作为实际执行命令的“触发器”的命令。关键是“懒惰评价”;在流畅的界面中,除非必要,否则什么都不应该做;这样你就可以控制事情发生的时间。
In a sentence, your code is too "eager". The InvokeMethod method is called, and performs the action, before your fluent grammar structure tells your code how many times it should repeat.
To change this, try also specifying the method you are invoking as a private field in your methodInvoker, then include a command that is a "trigger" to actually perform the commands. The key is "lazy evaluation"; in a fluent interface, nothing should be done until it has to; that way you have most of the control over when it does happen.