在MATLAB中为相关属性动态分配getter [英] Dynamically assign the getter for a dependent property in MATLAB
问题描述
在Matlab中,我可以这样定义一个类:
In Matlab, I can define a class as such:
classdef klass < handle
properties(Dependent)
prop
end
end
Matlab非常高兴地实例化此类的对象,即使没有为prop
定义getter.只有当我尝试访问它时,它才会失败(可以理解).我想根据属性名称动态设置GetMethod
.
Matlab is perfectly happy instantiating an object of this class, even without defining a getter for prop
. It only fails when I try to access it (understandably). I'd like to set the GetMethod
dynamically based upon the property's name.
不幸的是,即使该属性是从属的,GetMethod
的meta.property
字段仍然是只读的.尽管从dynamicprops
继承可以允许添加一个属性,并在每个实例中以编程方式设置其GetMethod,但我认为它不能用于更改现有属性.我可能必须走这条路线,但是由于每个对象都必须存在prop
,所以我希望只在逐个类的基础上简单地设置getter.这样的事情有可能吗?
Unfortunately, even when the property is Dependent, the meta.property
field for GetMethod
is still read-only. And while inheriting from dynamicprops
could allow adding a property and programmatically setting its GetMethod in every instance, I don't believe it could be used to change an existing property. I may have to go this route, but as prop
must exist for every object I'd prefer to simply set the getter on a class-by-class basis. Is such a thing possible?
另一种解决方案是通过某种包罗万象"方法.在其他语言中,这可以通过类似Ruby的 method_missing
或类似于PHP的方法来完成. __get()
.但是据我所知,Matlab中没有(已记录或其他方式)类似物.
An alternative solution could be through some sort of catch-all method. In other languages, this could be accomplished through a Ruby-like method_missing
or a PHP-like __get()
. But as far as I know there's no (documented or otherwise) analog in Matlab.
(我的用例:此类被许多用户定义的子类继承,并且它们的所有依赖属性都以类似的方式访问,只是根据属性名称进行更改.而不是要求用户编写get.*
方法包装调用它们的每个依赖属性的通用代码,我想使用包含必要元数据的匿名函数指针对它们进行动态设置.
(My use case: this class gets inherited by many user-defined subclasses, and all their dependent properties are accessed in a similar way, only changing based on the property name. Instead of asking users to write get.*
methods wrapping a call to the common code for each and every one of their dependent properties, I'd like to set them all dynamically with anonymous function pointers containing the necessary metadata).
推荐答案
这是我的建议:在超类中创建一个名为add_dyn_prop
的方法.该方法将在子类中调用,而不是创建依赖财产是通常的方式.
Here is my proposal: create a method in the superclass called add_dyn_prop
. This method is to be called in the subclasses instead of creating a dependent property the usual way.
这个想法是超类继承自 dynamicprops
和使用 addprop
到
The idea is that the superclass inherit from dynamicprops
and use addprop
to add a new property, and set its accessor methods manually based on its name.
classdef klass < dynamicprops
methods (Access = protected)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
% NOTE: this has to be a simple function_handle (@fun), not
% an anonymous function (@()..) to avoid infinite recursion
p.GetMethod = @get_method;
p.SetMethod = @set_method;
% nested getter/setter functions with closure
function set_method(obj, val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
现在在子类中,而不是像通常那样定义一个依赖属性,我们在构造函数中使用这个新的继承函数来定义一个动态属性:
now in the subclass, instead of defining a dependent property the usual way, we use this new inherited function in the constructor to define a dynamic property:
classdef subklass < klass
%properties (Dependent, SetAccess = private)
% name
%end
%methods
% function val = get.name(obj)
% val = 'Amro';
% end
%end
methods
function obj = subklass()
% call superclass constructor
obj = obj@klass();
% define new properties
add_dyn_prop(obj, 'name', 'Amro');
add_dyn_prop(obj, 'age', [], false)
end
end
end
输出:
>> o = subklass
o =
subklass with properties:
age: []
name: 'Amro'
>> o.age = 10
o =
subklass with properties:
age: 10
name: 'Amro'
>> o.name = 'xxx'
You cannot set the read-only property 'name' of subklass.
当然,现在您可以根据最初想要的属性名称来自定义getter方法.
Of course now you can customize the getter method based on the property name as you initially intended.
根据评论,请在下面找到与上述讨论的相同技术的细微变化.
Based on the comments, please find below a slight variation of the same technique discussed above.
这个想法是要求子类创建一个属性(在超类中定义为抽象),其中包含要创建的所需动态属性的名称.然后,超类的构造函数将创建指定的动态属性,将其访问器方法设置为泛型函数(可以根据您的请求根据属性名称自定义其行为).我正在重用前面提到的相同的add_dyn_prop
函数.
The idea is to require the subclass to create a property (defined as abstract in the superclass) containing the names of the desired dynamic properties to be created. The constructor of the superclass would then create the specified dynamic properties, setting their accessor methods to generic functions (which could customize their behavior based on the property name as you requested). I am reusing the same add_dyn_prop
function I mentioned before.
在子类中,只需要实现继承的抽象dynamic_props
属性,并使用名称列表(或者如果您不想创建任何动态属性,则使用{}
)进行初始化.例如,我们写:
In the subclass, we are simply required to implement the inherited abstract dynamic_props
property, initialized with a list of names (or {}
if you dont want to create any dynamic property). For example we write:
classdef subklass < klass
properties (Access = protected)
dynamic_props = {'name', 'age'}
end
methods
function obj = subklass()
obj = obj@klass();
end
end
end
超类类似于我们之前的类,只是现在它有责任在其构造函数中为每个属性名称调用add_dyn_prop
:
The superclass is similar to what we had before before, only now is it its responsibility to call the add_dyn_prop
in its constructor for each of the property names:
classdef klass < dynamicprops % ConstructOnLoad
properties (Abstract, Access = protected)
dynamic_props
end
methods
function obj = klass()
assert(iscellstr(obj.dynamic_props), ...
'"dynamic_props" must be a cell array of strings.');
for i=1:numel(obj.dynamic_props)
obj.add_dyn_prop(obj.dynamic_props{i}, [], false);
end
end
end
methods (Access = private)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
%p.Transient = true;
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
p.GetMethod = @get_method;
p.SetMethod = @set_method;
% nested getter/setter functions with closure
function set_method(obj,val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
注意:我没有使用 ConstructOnLoad
类属性或 Transient
属性属性,因为我仍然不确定它们将如何影响关于动态属性的从保存的MAT文件中加载对象.
Note: I did not use ConstructOnLoad
class attribute or Transient
property attribute, as I am still not sure how they would affect loading the object from a saved MAT-file in regards to dynamic properties.
>> o = subklass
o =
subklass with properties:
age: []
name: []
>> o.name = 'Amro'; o.age = 99
o =
subklass with properties:
age: 99
name: 'Amro'
这篇关于在MATLAB中为相关属性动态分配getter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!