Instantiate class from name in MATLAB

后端 未结 4 1966
一整个雨季
一整个雨季 2020-12-31 07:31

I\'m trying to list classes I created in some folder in my Matlab folder - using only their name (class name)

as an example, I have a class called \'SimpleString\' -

相关标签:
4条回答
  • 2020-12-31 08:08

    Use a package to access class constructors with .()-notation.

    A Matlab package is simply a folder/directory with a name that begins with +:

    +mypackage/foo.m:

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

    With class foo defined this way, you can access the constructor of mypackage.foo as

    class_name = 'foo';
    o = mypackage.(class_name)('arg1_value', 'arg2_value');
    
    0 讨论(0)
  • 2020-12-31 08:15

    Use str2func to get a function handle to the constructor. You can then call it with whatever arguments are appropriate.

    >> 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
    
    0 讨论(0)
  • 2020-12-31 08:19

    You can use the WHAT function to discover classes (as well as functions,packages,etc...) in a certain folder, then call METHODS to find the signature of the constructor of the class (some parsing needed here), finally using FEVAL (passing arguments if any) to create an object from this class.

    You could also use meta.class to get all sorts of meta-information about your classes.


    EDIT

    Here is some code to illustrate what I had in mind:

    %# 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
    

    As you can see, I found it easier to simply use meta.class to get metadata about the classes, instead of manually parsing the output of methods('fcn','-full') as I originally suggested.

    However this is not perfect, as there is no way to find out what type of input each constructor expect (only how many). I opted to always pass 0 for each argument..

    To test the implementation above, I create these sample classes (one in a self-contained file, the other defined in @-folder with multiple files):

    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
    

    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
    

    folder/@hello2/say.m

    function say(obj)
        fprintf('Hello2 %s!\n', obj.name);
    end
    
    0 讨论(0)
  • 2020-12-31 08:24

    You can use eval to instantiate the class using just the class name.

    instance = eval('SimpleString');
    

    However, if you're simply iterating through all the m-files in a folder containing class definitions and grabbing the file names, you'll only be able to invoke the default constructor using this method.

    0 讨论(0)
提交回复
热议问题