【发布时间】:2011-10-29 11:47:11
【问题描述】:
我正在尝试列出我在 Matlab 文件夹的某个文件夹中创建的类 - 仅使用它们的名称(类名)
例如,我有一个名为“SimpleString”的类 - 如果我只知道它的名称是“SimpleString”,我的目标是从该类实例化一个对象
因此,我想实时找出文件夹中有哪些类(完成),然后能够实例化任何这些类(我的问题) 谢谢
【问题讨论】:
标签: oop class matlab dynamic instantiation
我正在尝试列出我在 Matlab 文件夹的某个文件夹中创建的类 - 仅使用它们的名称(类名)
例如,我有一个名为“SimpleString”的类 - 如果我只知道它的名称是“SimpleString”,我的目标是从该类实例化一个对象
因此,我想实时找出文件夹中有哪些类(完成),然后能够实例化任何这些类(我的问题) 谢谢
【问题讨论】:
标签: oop class matlab dynamic instantiation
您可以使用eval 仅使用类名来实例化该类。
instance = eval('SimpleString');
但是,如果您只是遍历包含类定义的文件夹中的所有 m 文件并获取文件名,您将只能使用此方法调用默认构造函数。
【讨论】:
eval 可用于执行任意 MATALB 代码,有人可以很容易地溜进 eval('delete(''*.m'')') 并删除所有代码文件。 feval 使用起来更安全,虽然 feval('delete', '*.m') 可以使用,但使用起来稍微困难一些。
你可以使用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 中定义,具有多个文件):
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
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
function say(obj)
fprintf('Hello2 %s!\n', obj.name);
end
【讨论】:
使用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
【讨论】:
使用 包 访问带有.()-notation 的类构造函数。
Matlab package 只是一个名称以+ 开头的文件夹/目录:
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 更好的选择。