在过程化代码中调用Execute之前,我应该检查ICommand的CanExecute方法吗?

9
在XAML中使用“ ICommand”时,WPF使用“ CanExecute”方法来启用或禁用与命令相关联的控件。但是,如果我从过程性代码中调用“ Execute”,我应该首先检查“ CanExecute”以确保命令可以执行,还是应该让“ Execute”为我处理此检查?
换句话说,我应该这样做:
if (someCommand.CanExecute(parameter, target))
    someCommand.Execute(parameter, target);

或者只需要这个:
someCommand.Execute(parameter, target);

1
为什么不将这部分加入Execute()函数呢? - Jerry Nixon
3个回答

8

良好的编程风格应该要求您首先检查CanExecute方法是否可用。这将实施适当的分解和一致的实现。此外,如果您想要将此命令绑定到按钮,则它将按预期工作。


2
从合同上来看,这感觉更“正确”。我还要补充一点,如果您正在检查的条件在任何方面依赖于命令外部的状态(因此可以被另一个线程修改等),则需要在CanExecute/Execute序列周围加锁。 - JerKimball

5

您只需要调用Execute,让命令实现处理验证。CanExecute主要提供UI状态绑定。

即使您首先调用CanExecute,除了非常简单的单线程情况之外,仍然可能存在竞态条件,导致CanExecute和Execute调用之间的命令有效性发生变化,使对CanExecute的调用没有意义。


2
正如你刚才指出的那样,它们不一定按顺序执行,即使它们按顺序执行,还有什么阻止另一个线程在这两个连续调用之间更改命令的基础数据或状态呢?而命令实现知道它正在操作的上下文,并且如果需要,可以原子地同步访问共享数据。它还能够最好地确定命令在执行时是否有效。 - Stu Mackellar
2
如果对数据进行同步访问,那么数据就不会发生变化。我的观点是,只有命令实现才能知道是否需要这样做。此外,“容易出现竞态条件的领域”这种说法是不存在的:要么存在对数据的并发访问,需要保护数据,要么不存在。你似乎在争论这种类型的竞态条件很少发生,因此可以忽略它们。这是一种危险的态度——如果有数百万用户运行程序,问题发生的可能性趋近于必然。 - Stu Mackellar
1
@JerKimball:你可以认为CanExecute只是用来提供信息(被WPF这样的框架使用)关于一个Command能否执行,而且Executed不能依赖于CanExecute被检查,除非Execute本身调用了CanExecute。至少,没有保证程序员在调用Execute之前会检查CanExecute。你对这个论点有什么看法? - Matthew
1
作为第三种选择:不妨两者兼顾(既调用CanExecute,又在Execute中进行验证)?这样,编写命令的人就无需依赖使用命令的人先检查CanExecute。同时,使用命令的人也可以确信代码将按预期工作,而无需知道Executed还进行了验证。 - Matthew
1
@Matthew - 嗯...你说得有道理,其他框架/库中的“命令”概念通常不区分CanExecute/Execute...我不知道,我还没有决定:从语义上讲,将两者分开似乎是正确的,如果执行命令的成本与“仅检查”的成本相比过高,则将两者分开确实是有意义的,但实际上,我同意大多数人不会记得调用两者。 - JerKimball
显示剩余3条评论

2

您需要先调用CanExecute方法,因为实现ICommand接口的类在其Execute方法中并没有检查CanExecute。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接