【问题标题】:Instantiate class from name in MATLAB在 MATLAB 中根据名称实例化类
【发布时间】:2011-10-29 11:47:11
【问题描述】:

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

例如,我有一个名为“SimpleString”的类 - 如果我只知道它的名称是“SimpleString”,我的目标是从该类实例化一个对象

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

【问题讨论】:

    标签: oop class matlab dynamic instantiation


    【解决方案1】:

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

    instance = eval('SimpleString');
    

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

    【讨论】:

    • 这对我的目标很有效——我已经涵盖了所有的“发现”和元数据。我只需要实例化。谢谢!
    • eval 可用于执行任意 MATALB 代码,有人可以很容易地溜进 eval('delete(''*.m'')') 并删除所有代码文件。 feval 使用起来更安全,虽然 feval('delete', '*.m') 可以使用,但使用起来稍微困难一些。
    • @Sam 是的,因为 稍微困难 足以阻止人们做恶意的事情 :) Amro 的回答比我的好,不知道为什么 OP 没有选择它一。
    【解决方案2】:

    你可以使用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
    

    如您所见,我发现简单地使用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
    

    文件夹/@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
    

    文件夹/@hello2/say.m

    function say(obj)
        fprintf('Hello2 %s!\n', obj.name);
    end
    

    【讨论】:

    • 对于包中的任何类,以您正在执行的方式查找构造函数都将失败,元类的 Name 属性将是 package.classname 而函数 Name 属性将只是类名
    【解决方案3】:

    使用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
    

    【讨论】:

    • 不错,简洁。如果有人有充分的理由不将其用于简单的情况,我很想听听。
    【解决方案4】:

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

    Matlab package 只是一个名称以+ 开头的文件夹/目录:

    +mypackage/foo.m:

    classdef foo
        methods
            function obj = foo(arg1, arg2)
                %foo constructor
            end
        end
    end
    

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

    class_name = 'foo';
    o = mypackage.(class_name)('arg1_value', 'arg2_value');
    

    【讨论】:

    • 这似乎是比使用eval 更好的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 2015-10-18
    • 1970-01-01
    • 2012-09-26
    • 2020-01-26
    相关资源
    最近更新 更多