我想将我的对象保存为 XML,以便其他应用程序可以读取和写入数据文件——这对于 Matlab 的二进制 mat 文件来说非常困难。
我遇到的根本问题是,Matlab 的反射等价物(我曾经在 .NET 中做过类似的事情)在私有属性方面不是很实用。Matlab 的struct(object)
函数提供了从对象编写 XML 方面的技巧,因为虽然我做不到
x = myInstance.myPrivateProperty;
...我可以
props = struct(myInstance);
x = props.myPrivateProperty;
因此,我可以使用下面的代码从任何对象创建一个纯(不包含对象)结构,然后使用纯结构编写 XML 文件很简单。
但是,有没有办法扭转这个过程?也就是说,使用下面代码保存的数据创建一个对象实例(该数据包含类实例的所有非依赖、非常量、非瞬态属性的列表,以及类的名称)?我正在考虑让我的所有对象都从一个名为 XmlSerializable 的类继承,该类将接受一个结构作为构造函数中的单个参数,然后将结构中包含的所有值分配给相应命名的属性。但是,这不起作用,因为如果 MyClass 继承了 XmlSerializable,则 XmlSerializable 中的代码不允许设置 MyClass 的私有属性(与我如何编写通用函数来操作私有属性有关?)。这在 .NET 中没有问题(参见是否可以通过反射设置私有属性?),但我无法在 Matlab 中弄清楚它。
此代码创建一个结构,其中包含传入对象的所有状态信息,但不包含对象实例。生成的结构可以简单地写入 XML:
function s = toPureStruct(thing)
if isstruct(thing)
s = collapseObjects(thing);
s.classname = 'struct';
elseif isobject(thing)
s.classname = class(thing);
warning off MATLAB:structOnObject;
allprops = struct(thing);
warning on MATLAB:structOnObject
mc = metaclass(thing);
for i=1:length(mc.PropertyList)
p = mc.PropertyList(i);
if strcmp(p.Name, 'classname')
error('toStruct:PropertyNameCollision', 'Objects used in toStruct may not have a property named ''classname''');
end
if ~(p.Dependent || p.Constant || p.Transient)
if isobject(allprops.(p.Name))
s.(p.Name) = toPureStruct(allprops.(p.Name));
elseif isstruct(allprops.(p.Name))
s.(p.Name) = collapseObjects(allprops.(p.Name));
else
s.(p.Name) = allprops.(p.Name);
end
end
end
else
error(['Conversion to pure struct from ' class(thing) ' is not possible.']);
end
end
function s = collapseObjects(s)
fnames = fields(s);
for i=1:length(fnames)
f = s.(fnames{i});
if isobject(f)
s.(fnames{i}) = toPureStruct(f);
elseif isstruct(f)
s.(fnames{i}) = collapseObjects(f);
end
end
end
编辑:我想阅读保存的文件的其他“应用程序”之一是版本控制系统(用于跟踪由 Matlab 对象定义的配置中的参数变化),因此任何可行的解决方案都必须能够生成人类可理解的文本。上面的 toPureStruct 方法在将结构转换为 XML 时执行此操作。