Matlab类设置方法调用意外

时间:2018-04-18 17:31:01

标签: matlab class oop

Matlab指定When [a] Set Method is Called

我遇到了奇怪的结果,所以我对下面的课进行了一系列测试:

% @cScenInsts/cScenInsts.m
%-------------------------

classdef cScenInsts < matlab.mixin.Copyable

properties
   TwinYrs = 5 % Default value
end % properties

methods

   function o = cScenInsts( TwinYrs_in ) % Constructor
      if exist('TwinYrs_in') && ~isempty( TwinYrs_in )
         o.TwinYrs = TwinYrs_in ;
      else
         o.TwinYrs = o.TwinYrs ;
      end % if
   end % function cScenInsts()

   function o = set.TwinYrs(o,TwinYrs_in)
      o.TwinYrs = TwinYrs_in;
      fprintf( '%s: Property TwinYrs = %g\n', mfilename, o.TwinYrs );
   end % function set.TwinYrs

end % methods

end % classdef

else块在这个最小工作示例中是多余的,但在现实生活中,我希望它调用set方法,该方法设置其他相关参数的值。

使用上面的类定义,我遇到了混合结果,看他们是否遵循调用set方法的规则。

以下命令中的UNEXPECTED行为:“将属性分配给在类定义中指定的默认值”不应该触发set方法,但确实如此。

>> o = cScenInsts;
   cScenInsts: Property TwinYrs = 5

同样,“作为优化,如果MATLAB确定属性值不会因引用属性的赋值而发生变化,则MATLAB不会调用属性集方法”。似乎如果属性在赋值的LHS和RHS上并且值没有改变,则不调用set方法。这应该适用于上面,因为它是执行的else块。上述结果表明它不适用,这就是我所寻求的效果。我的答案是,我不知道在所有情况下,当它看起来与优化条款相矛盾时,我对这种行为的可靠性有多大信心。

以下命令中的EXPECTED行为:

>> o = cScenInsts(3);
   cScenInsts: Property TwinYrs = 3

以下命令中的UNEXPECTED行为:“将属性分配给在类定义中指定的默认值”不应该触发set方法,但确实如此。

>> o = cScenInsts(5);
   cScenInsts: Property TwinYrs = 5

以下命令中的EXPECTED行为:

>> o.TwinYrs = 3;
   cScenInsts: Property TwinYrs = 3

以下命令中的EXPECTED行为,因为属性的AbortSet属性未设置为true

>> o.TwinYrs = 3;
   cScenInsts: Property TwinYrs = 3

以下命令中的UNEXPECTED行为:“将属性分配给在类定义中指定的默认值”不应该触发set方法,但确实如此。

>> o.TwinYrs = 5;
   cScenInsts: Property TwinYrs = 5

以下命令中的AMBIGUOUS行为:一方面,“[a]将属性设置为类定义中指定的默认值”不应该触发set方法,但确实如此。另一方面,它也可以被视为预期行为,因为属性的AbortSet属性未设置为true

>> o.TwinYrs = 5;
   cScenInsts: Property TwinYrs = 5

有人可以解释意外和/或含糊不清的结果吗?

2 个答案:

答案 0 :(得分:5)

我将解决您在未调用属性集方法时从this list个案例中提到的每个令人困惑的要点:

  •   

    加载类时初始化类定义中的默认值

    我相信这是指通过从MAT文件加载(即使用loadobj方法)来创建类对象。加载属性值时,只需复制它们而不将它们传递给set方法

  •   

    将属性指定为其在类定义

    中指定的默认值

    我相信这是指MATLAB 最初创建对象并设置其默认值时的具体内容。它不会先将值传递给任何set方法。要看到这一点,您可以将此行添加到类构造函数的最开头:

    disp(o);
    

    当您运行代码时,您会在进入构造函数之前看到已经为您创建了具有默认属性值的默认对象,然后您甚至对输入参数执行了任何操作。设置这些属性时不调用任何设置方法(如子弹点状态)。任何后续更改属性,就像在if-else语句中设置它们一样,DOES仍会按预期调用set方法。

    您可能会注意到,在这种情况下,您的else语句实际上是不必要的,因为已经设置了默认值。删除else语句将为您提供以下行为:

    o = cScenInsts;
    

    另外,由于您是matlab.mixin.Copyable类(具有handle类行为)的子类,因此您不需要从set方法返回对象:

    function set.TwinYrs(o, TwinYrs_in)
      ...
    


  •   

    作为优化,如果MATLAB确定属性值不会因引用属性的赋值而发生更改,则MATLAB不会调用属性集方法。

    这句话有点不清楚。正如您已经注意到的那样,保留AbortSet attribute未设置(即默认设置为false)意味着即使将属性设置为相同的值,仍会调用set方法。上面的陈述似乎表明,在某些情况下,即使AbortSet属性为false,MATLAB仍可能决定放弃调用set方法。如果是这样,则不清楚使用该优化的条件是什么。

如上所述删除else语句,以下是您上述某些示例的预期结果:

>> o = cScenInsts;  % Set method not invoked, default value used

>> o = cScenInsts(3);
cScenInsts: Property TwinYrs = 3  % Set method invoked, overriding default value

>> o = cScenInsts(5);
cScenInsts: Property TwinYrs = 5  % Set method invoked, even though same as default value
                                  %   (since AbortSet is false)
>> o.TwinYrs = 5;
cScenInsts: Property TwinYrs = 5  % Set method invoked, even though same as current value
                                  %   (since AbortSet is false)

答案 1 :(得分:1)

这是TMW的答案:

  

......声明:

     
    

“作为优化,如果MATLAB确定属性值     由于引用的赋值不会改变     属性,MATLAB不会调用属性集方法。“

  
     

......显然是不正确的。这种优化不存在 -   只有时间MATLAB才会因为赋值而放弃调用setter   更改值是“AbortSet”设置为true。&lt; ... snip ...&gt;

     

至于其他不明确的要点:

     
    

“加载时在类定义中初始化默认值     类“

  
     

这是指加载执行时发生的类定义   “?”或首次构建课程时。这是   解析和编译类定义并设置的步骤   可从的meta.property对象的DefaultValue属性   从?返回的meta.class对象。这什么都没有   从MAT-File或loadobj加载类的实例。

     
    

“将属性分配给其中指定的默认值     类定义“

  
     

这个子弹意味着在MATLAB时不调用set-function   在创建新实例时为属性分配默认值   一类。这是指在期间分配默认值   属性初始化。正如我们所怀疑的那样,它并不是指任何   对值恰好等于默认值的其他赋值   值。

     

我将继续提交文档更新请求...

谢谢大家的光临。