抽象类的静态方法中的类名

时间:2016-03-03 13:27:53

标签: matlab

我想访问调用抽象超类中实现的静态方法的具体类的类名。

这是抽象超类的代码(部分):

classdef (Abstract) AbstractJobProcessor < handle

    properties (Abstract, Constant)
        VERSION_MAJOR;
        VERSION_MINOR;
        LAST_MODIFIED;
    end 

    ...


methods (Static)
    function res = getVersionMajor;
        res = AbstractJobProcessor.VERSION_MAJOR;
    end 

    function res = getVersionMinor
        res = AbstractJobProcessor.VERSION_MINOR;
    end

    function res = getVersionInfo
        res = sprintf('**CLASSNAME**: v%d.%02d (last modified: %s)',... 
            AbstractJobProcessor.VERSION_MAJOR,...
            AbstractJobProcessor.VERSION_MINOR,...
            AbstractJobProcessor.LAST_MODIFIED);
    end

end
...

基本上,我想访问具体子类的类名,并在方法getVersionInfo中使用它来代替字符串**CLASSNAME**

返回有关类的元信息的所有方法(我在文档中找到)都需要引用类的实例(例如,mc = metaclass(object))。

2 个答案:

答案 0 :(得分:1)

下面的函数将为您提供所需的内容 - 在调用(继承的)静态超类方法时使用的子类名称。只需在您的超类方法中调用它,就像使用任何普通函数一样:

className = getStaticCallingClassName();

做什么处理:

  • 以编程方式(即通过正在运行的脚本/函数)调用方法的情况,以及从命令窗口调用方法的情况。
  • 任意嵌套的包名称(即位于以+为前缀的目录中的类。)

无法处理的内容:

  • 如果在非静态上下文中调用静态方法(即在对象实例上),则不起作用。但是你不应该使用这样的语法。如果我们能够递归地使用evalin'caller'工作空间,这将是可能的,但它不会以这种方式工作。

该想法背后的简要说明:由dbstack生成的堆栈跟踪中的第二个条目将对应于超类,我们可以使用它来提取静态方法名称。接下来的步骤取决于:

  1. 如果以编程方式调用该方法,则第三个堆栈条目会指向我们需要读取的父脚本/函数中的一行,例如使用dbtype。剩下要做的就是根据方法名称使用regexp提取子类名称。
  2. 如果从命令窗口调用该方法,我们查询最后一个命令并将其用作正则表达式的输入。
  3. 请注意,即使堆栈有3个或更多条目,也不意味着以编程方式调用该方法。例如,如果我们在某个地方停止断点并从命令窗口调用该方法,则堆栈跟踪将很长,但基于第三个堆栈跟踪条目中的行的regexp将不会给出答案。在这种情况下,我们回到命令窗口方法。

    警告:它严重依赖于未记录的功能,可能会在任何功能发布中出现问题。在Matlab 2015b上测试过,但也应该适用于大多数以前的版本。有人可能会说它很脏,但效果很好,而且这是我意识到实现这种行为的唯一方法。

    function [className, fullPath] = getStaticCallingClassName()
        ST = dbstack('-completenames');
        % First one is getStaticCallingClassName, second one is the superclass
        methodName = char(regexp(ST(2).name, '[^\.]([^.]*)$', 'match'));
        % matches string (combination of alphanumeric/underscore/dot characters) preceeding the given method call.
        pattern = sprintf('[\\w.-]*(?=.%s)', methodName);
    
        % If the parent called static method programmatically, we should be able to find it via the next (third) stack trace
        if length(ST) > 2
            command = evalc('dbtype(ST(3).file, num2str(ST(3).line))');
            className = char(regexp(command, pattern, 'match'));
        else % was likely called from command window. Long stack trace means that we're simply waiting in a breakpoint somewhere
            className = []; % go straight to command window approach
        end
    
        if isempty(className) % means that static method was called directly from command window
            javaHistory = com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory();
            command = char(javaHistory(end));
            className = char(regexp(command, pattern, 'match'));
        end
    
        fullPath = which(className);
    end
    

答案 1 :(得分:1)

这是解决方法。根据MATLAB文档:

  • &#39; 普通的方法定义了对类的对象进行操作的函数&#39;,
  • &#39; 静态方法是(1)与类相关联,但(2)不与该类的特定实例相关联。

如果使用空对象数组调用普通方法,则可以使用静态方法的两个方面。

例如,假设我们有一个基类:

classdef base
    methods 
        function obj = base()
            disp('constructor called')
        end
        function dispClassName(obj)
            disp(['class name = ', class(obj)]);
        end
    end
end

和子类

classdef sub < base
end

现在调用方法如下(这不会调用任何构造函数):

>> base.empty.dispClassName
class name = base
>> sub.empty.dispClassName
class name = sub

一个真正的解决方案(我为MathWorks做了一个增强请求03315500)将扩展MATLAB语言的方法属性&#39; Class&#39;定义与调用类关联的方法(类似于Python @classmethod装饰器)。此类的方法将自动接收调用函数的元类作为第一个参数。有了这样的扩展,我们可以定义一个基类:

% Future MATLAB syntax extension
classdef base
    methods(Class) % New method attribute ‘Class’
        function dispClassName(cls) % implicit argument (meta.class)
            disp(['class name = ' cls.Name ]);
        end
    end
end

和子类

classdef sub < base
end

并致电

>> base.dispClassName
class name = base
>> sub.dispClassName
class name = sub