简体   繁体   English

在表达式绑定的属性中调用新的RelayCommand(ICommand)是否安全?

[英]Is it safe to call new RelayCommand (ICommand) in Expression-Bodied Properties

With expression bodied properties we can create a RelayCommand as follows 通过表达式的属性,我们可以创建一个RelayCommand ,如下所示

public RelayCommand Command => _command ?? (_command = new RelayCommand(CommandExecute));

However this is possible also 但是,这也是可能的

public RelayCommand Command => new RelayCommand(CommandExecute);

Obviously this creates a new RelayCommand every time the Property getter is called. 显然,这在每次调用属性getter都会创建一个新的RelayCommand。 Though there is comments i have seen around that says the underlying plumbing only creates one command... 尽管有评论我说周围的管道仅创建一个命令...

Does anyone have a definitive answer on this? 有人对此有明确的答案吗?

Does anyone have a definitive answer on this? 有人对此有明确的答案吗?

The documentation does not promise to only retrieve the property value once. 该文档不保证只检索一次属性值。 So, you must assume it could retrieve it more than once. 因此,您必须假定它可以多次检索它。

Of course, in practice this assumed behavior may never occur. 当然,实际上,这种假定的行为可能永远不会发生。 It would make perfect sense that a property, once retrieved, would never be retrieved again if property-changed notification never happened for that property, and of course a read-only property will never have a property-changed notification. 完全有道理的是,如果某个属性从未发生过属性更改的通知,则一旦检索到该属性,就永远不会再次检索该属性,当然,只读属性也不会具有属性更改的通知。

So you can probably get away with it. 因此,您可能可以摆脱它。 But personally, I wouldn't risk it. 但就我个人而言,我不会冒险。 If the underlying implementation changes, or your assumption is wrong for any reason, having two or more instances of the same command is going to be a problem, at least if that command ever raises the CanExecuteChanged event. 如果基础实现发生了变化,或者由于某种原因您的假设是错误的,那么至少有一个命令引发CanExecuteChanged事件的情况下,使用同一命令的两个或多个实例将是一个问题。 I mean, I guess if the CanExecute() state never changes, you can have as many copies of the object as you want, and they'll all work exactly the same. 我的意思是,我想如果CanExecute()状态永远不会改变,那么您可以根据需要拥有任意数量的对象副本,并且它们的工作原理完全相同。 But if it can change, then you could wind up raising the event on the wrong command object, one that no one is listening to. 但是,如果它可以更改,则可能导致在错误的命令对象上引发该事件,而没人在听。

This is not just academic. 这不只是学术上的。 Not only could Microsoft, or some other implementer of a XAML/MVVM-based API your code might one day be used with, choose to forego storing the command object reference and instead count on being able to always retrieve it from the model object, it is common practice within the model object itself to retrieve the command object from the property. Microsoft或您的代码有一天可能会与Microsoft或基于XAML / MVVM的API的某些其他实现者一起使用,选择放弃存储命令对象引用,而是指望始终能够从模型对象中检索它,它不仅可以在模型对象本身中的常见做法是从属性中检索命令对象。 Scenarios where the command property is read multiple times are entirely plausible and worth worrying about. 多次读取命令属性的情况是完全合理的,值得担心。

More to the point, I don't see the motivation behind either option. 更重要的是,我看不到任何一种选择背后的动机。 The "create a new one each time" seems clearly wrong to me, even if you can get away with it. 即使您可以摆脱困境,“每次都创建一个新的”似乎对我来说显然是错误的。 And lazy initialization seems like over-complicated code for no benefit. 惰性初始化似乎过于复杂,没有任何好处。 After all, immediately after the model object is created, the next thing that almost always happens is that the properties are bound to UI, and so the command property is going to be retrieved at that time. 毕竟,在创建模型对象之后,几乎总是发生的下一件事是将属性绑定到UI,因此将在那时检索command属性。 Lazy initialization will delay initialization of the underlying field by milliseconds at most (and usually much less time than that). 延迟初始化最多会将基础字段的初始化延迟毫秒(通常比这要少得多)。

And if you forego lazy init, you get to use automatic properties: 如果您放弃惰性初始化,就可以使用自动属性:

public RelayCommand Command { get; } = new RelayCommand(CommandExecute);

No explicit field! 没有明确的领域! Much nicer, IMHO. 更好,恕我直言。

Noting, of course, that to use that syntax CommandExecute() would have to be a static member. 当然,要注意使用CommandExecute()语法必须是static成员。 Most commands do need access to the model instance and so the above wouldn't work for those. 大多数命令确实需要访问模型实例,因此上面的命令不适用于这些实例。

It's possible one reason the lazy-init pattern got popular is that it allows use of field initializer syntax, as a loophole over the usual "not allowed to use instance members in field initializers" rule. 惰性初始化模式流行的一个可能原因是它允许使用字段初始化程序语法,这是对通常的“不允许在字段初始化程序中使用实例成员”规则的漏洞。

Personally, I'd still opt for in-constructor initialization (which works fine for read-only automatic properties…you still don't need the explicit backing field) for commands that use the current instance. 就我个人而言,对于使用当前实例的命令,我仍然会选择构造函数内初始化(这对于只读自动属性很好,但是您仍然不需要显式的后备字段)。 Lazy-init seems like a premature and false optimization in this scenario. 在这种情况下,惰性初始化似乎是过早错误的优化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM