在Matlab中可以实现自定义通用对象序列化吗?

时间:2012-10-11 01:03:37

标签: oop matlab

我想将我的对象保存为XML,以便其他应用程序可以读取和写入数据文件 - 这对于Matlab的二进制mat文件非常困难。

我遇到的根本问题是Matlab相当于反射(我曾经在.NET中做类似的事情)在私有属性方面不是很有用。 Matlab的struct(object)函数在从对象编写XML方面提供了一个hack,因为我无法做到

x = myInstance.myPrivateProperty;

......我可以做到

props = struct(myInstance);
x = props.myPrivateProperty;

因此,我可以使用下面的代码从任何对象创建一个纯(包含无对象)结构,然后使用纯结构编写XML文件是微不足道的。

但是,有没有办法扭转这个过程?也就是说,使用下面代码保存的数据创建一个对象实例(该数据包含类实例的所有非依赖,非常量,非瞬态属性和类名称的列表)?我正在考虑让我的所有对象继承自一个名为XmlSerializable的类,该类将接受结构作为构造函数中的单个参数,然后将结构中包含的所有值分配给相应命名的属性。但是,这不起作用,因为如果MyClass继承XmlSerializable,则不允许XmlSerializable中的代码设置MyClass的私有属性(与How can I write generalized functions to manipulate private properties?相关)。这在.NET中没有问题(参见Is it possible to set private property via reflection?),但我在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时执行此操作。

2 个答案:

答案 0 :(得分:1)

您可以通过为保存的对象使用新的v7.3 MAT文件格式来回避此问题。与较旧的MAT文件格式不同,v7.3是HDF5的变体,并且有HDF5支持和其他语言的库。这可能会少得多,而且你可能也会获得更好的性能,因为HDF5将比天真的XML更有效地表示数值数组。

这不是默认格式;您可以使用-v7.3切换到save功能启用它。

答案 1 :(得分:0)

据我所知,在Matlab 2011b中我不想做什么。根据@Andrew Janke的回答,有可能使用Matlab的二进制HDF5文件加载命令做类似的事情,可以被其他程序读取和修改。但是,这增加了大量的复杂性,因为即使是最简单的类,Matlab的HDF5表示也非常不透明。例如,如果我在Matlab中使用两个标准属性(prop1和prop2)创建SimpleClass classdef,则使用-v7.3开关生成的HDF5二进制文件为7k,扩展的XML为21k,文本“prop1”和“ prop2“不要出现在任何地方。我真正想从SimpleClass创建的是:

<root>
  <classname>SimpleClass</classname>
  <prop1>123</prop1>
  <prop2>456</prop2>
</root>

我认为不可能在Matlab中以通用方式从类属性中生成上述文本,即使例如在.NET或Java中也是如此。