在MATLAB中为相关属性动态分配getter [英] Dynamically assign the getter for a dependent property in MATLAB

查看:68
本文介绍了在MATLAB中为相关属性动态分配getter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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.

不幸的是,即使该属性是从属的,GetMethodmeta.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆