在MATLAB中从名称实例化类

Ala*_*ban 12 oop matlab class dynamic instantiation

我正在尝试列出我在Matlab文件夹中的某个文件夹中创建的类 - 仅使用其名称(类名)

作为一个例子,我有一个名为'SimpleString'的类 - 我的目标是从该类实例化一个对象,如果我知道它的名字是'SimpleString'

所以实时,我想找出文件夹中的类(完成),然后能够实例化任何这些类(我的问题)谢谢

Jan*_*nus 12

使用 来访问带有.()-notation的类构造函数.

一个matlab程序包是简单地与开头的名称的文件夹/目录+:

+ mypackage的/ foo.m:

classdef foo
    methods
        function obj = foo(arg1, arg2)
            %foo constructor
        end
    end
end
Run Code Online (Sandbox Code Playgroud)

使用foo这种方式定义类,您可以访问mypackage.fooas 的构造函数

class_name = 'foo';
o = mypackage.(class_name)('arg1_value', 'arg2_value');
Run Code Online (Sandbox Code Playgroud)


kwa*_*ord 10

str2func得到的功能句柄来构造.然后,您可以使用适当的参数调用它.

>> m = str2func('containers.Map')
m = 
    @containers.Map
>> x = m({'foo', 'bar'}, {0, 1})
x = 
  containers.Map handle
  Package: containers

  Properties:
        Count: 2
      KeyType: 'char'
    ValueType: 'double'
  Methods, Events, Superclasses
Run Code Online (Sandbox Code Playgroud)


Amr*_*mro 6

你可以使用WHAT函数来发现某个文件夹中的类(以及函数,包等),然后调用METHODS来找到类的构造函数的签名(这里需要一些解析),最后使用FEVAL(传递参数,如果有的话)从这个类创建一个对象.

您还可以使用meta.class获取有关类的各种元信息.


编辑

这里有一些代码来说明我的想法:

%# folder containing your classes
pathName = fullfile(pwd,'folder');

%# make sure it is on the path
p = textscan(path, '%s', 'Delimiter',';'); p=p{1};
if ~any(ismember(p,pathName))
    addpath(pathName)
end

%# list MATLAB files
w = what(pathName);

%# get class names
fNames = cellfun(@(s) s(1:end-2), w.m, 'Uni',false);     %# remove .m extension
fNames = [fNames ; w.classes];        %# add classes in @-folders

%# get classes metadata
mt = cellfun(@meta.class.fromName, fNames, 'Uni',false); %# get meta-data
mt = mt( ~cellfun(@isempty,mt) );     %# get rid of plain functions

%# build object from each class
objects = cell(numel(mt),1);
for i=1:numel(mt)
    %# get contructor function
    ctorMT = findobj(mt{i}.MethodList, 'Access','public', 'Name',mt{i}.Name);

    %# get number of contructor arguments
    numArgs = numel(ctorMT.InputNames);

    %# create list of arguments (using just zeros)
    args = repmat({0}, [numArgs 1]);

    %# create object
    try
        obj = feval(ctorMT.Name,args{:});
    catch ME
        warning(ME.identifier, ME.message)
        obj = [];
    end

    %# store object
    objects{i} = obj;
end
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我发现简单地使用它meta.class来获取有关类的元数据更容易,而不是methods('fcn','-full')像我最初建议的那样手动解析输出.

然而,这并不完美,因为没有办法找出每个构造函数期望的输入类型(只有多少).我选择总是传递0每个参数..

为了测试上面的实现,我创建了这些示例类(一个在自包含文件中,另一个在@ -folder中定义,包含多个文件):

文件夹/ hello.m

classdef hello
    properties
        name = '';
    end
    methods
        function this = hello()
            this.name = 'world';
        end
        function val = get.name(obj)
            val = obj.name;
        end
        function obj = set.name(obj,val)
            obj.name = val;
        end
        function say(obj)
            fprintf('Hello %s!\n',obj.name);
        end
    end
end
Run Code Online (Sandbox Code Playgroud)

folder/@hello2/hello2.m

classdef hello2
    properties
        name
    end
    methods
        function this = hello2(val)
            this.name = val;
        end
        function val = get.name(obj)
            val = obj.name;
        end
        function obj = set.name(obj,val)
            obj.name = val;
        end
    end
    methods
        say(obj)
    end
end
Run Code Online (Sandbox Code Playgroud)

folder/@hello2/say.m

function say(obj)
    fprintf('Hello2 %s!\n', obj.name);
end
Run Code Online (Sandbox Code Playgroud)


Pra*_*ian 3

您可以eval仅使用类名来实例化该类。

instance = eval('SimpleString');
Run Code Online (Sandbox Code Playgroud)

但是,如果您只是迭代包含类定义的文件夹中的所有 m 文件并获取文件名,则只能使用此方法调用默认构造函数。

  • `eval` 可用于执行任意 MATALB 代码,有人可以很容易地插入 `eval('delete(''*.m'')')` 并删除所有代码文件。虽然可以使用“feval('delete', '*.m')”,但“feval”使用起来更安全,但稍微难一点。 (2认同)