无法从默认构造函数反序列化为“ this”吗?

时间:2019-03-04 13:55:46

标签: c# .net serialization xml-serialization

情况:

我有一个绑定到“设置”视图的ViewModel,应该让用户输入许多个性化设置,并且应该能够将它们保存为预设并加载它们。为此,ViewModel包含预设数据模型的集合,这些数据模型本身具有不同的属性,类对象等。 该计划是通过对整个ViewModels进行xml序列化和反序列化来实现保存所有预设的。

代码/问题

从ViewModel的构造方法中,我调用以下方法:

private void InitializePresetsFromFile()
{
    if (!File.Exists(Info.GetDefaultColorPalettePresetsXml()))
    {
        SetupNewEmpty();
        SerializePresets(Info.GetDefaultColorPalettePresetsXml());
    }
    else
    {
        DeserializePresets(Info.GetDefaultColorPalettePresetsXml());
    }
}

因此,该方法检查保存该预设的文件是否存在-如果不存在,则应设置一个空的预设并将其保存到新创建的文件中,否则应从现有文件中加载该预设。

序列化过程运行良好,但是由于我序列化为this,反序列化存在问题:

private void DeserializePresets(string path)
{
    XmlSerializer deserializer = new XmlSerializer(typeof(LinearAxisColorPresetsViewModel));
    TextReader reader = new StreamReader(path);
    object obj = deserializer.Deserialize(reader);
    LinearAxisColorPresetsViewModel XmlData = (LinearAxisColorPresetsViewModel)obj;
    reader.Close();
    VolumePresetList = XmlData.VolumePresetList;
    WaveShapePresetList = XmlData.WaveShapePresetList;
    VolumePresetSelectedIndex = XmlData.VolumePresetSelectedIndex;
    WaveShapePresetSelectedIndex = XmlData.WaveShapePresetSelectedIndex;
}

这里的问题是,由于我直接从构造函数中调用方法InitializePresetsFromFile(),所以反序列化器会在永无止境的循环中调用自己,从而导致stackoverflow错误。

因此,最简单的解决方案应该是使用另一个带有参数的构造函数,我在其中调用InitializePresetsFromFile(),对吗?这里的问题是ViewModel类是在相应View的xaml中直接实例化的:

<UserControl.Resources>
    <ResourceDictionary>
        <vm:LinearAxisColorPresetsViewModel x:Key="vm" />
    </ResourceDictionary>
</UserControl.Resources>

This posts的第二个答案表明约定是,从XAML调用的构造函数应该是无参数的,我想坚持这一点。

问题:

问题仅是如何根据最佳实践解决此问题。由于这是我对序列化和反序列化的首次尝试,因此我担心自己在这里走错了路。我的感觉是只有数据模型类应该序列化。我的ViewModel拥有两个此类的ObservableCollection,但是我想序列化完整的集合以及ViewModel中的其他属性(例如,选定的索引)。

2 个答案:

答案 0 :(得分:2)

您确实已经达到必须决定如何继续的地步。您现在正在做什么将无法工作。在这种情况下,XML序列化程序和XAML都使用默认构造函数。您不能在这里将其用于两个目的。

我的建议是创建一个类,该类反映用于反序列化XML文件的视图模型中的属性。此类仅需要属性,仅此而已。

如果视图模型类实际上是静态的,则可以使用a locator class将其绑定到。

答案 1 :(得分:0)

首先,您不应在类的构造函数中调用InitializePresetsFromFile方法。构造函数必须尽可能快,并且不会引起副作用。在构造函数中读取文件是一个坏习惯:如果不访问文件系统,就无法创建类的实例。这意味着您的代码不可测试,容易出错(例如,您是否想到突然的UnauthorizedAccessException?),而且速度很慢。

相反,创建一个公共方法以反序列化文件中的数据。这将破坏您无休止的递归。

如何调用该方法?

  • 您真的需要资源字典中的LinearAxisColorPresetsViewModel实例吗?如果没有,只需将反序列化的实例分配给视图的DataContext属性。
  • 如果确实需要,请在视图模型中创建一个ICommand,例如InitializeCommand使用上述方法从文件初始化内部状态;在应用启动/查看显示等时执行该命令。您可以使用例如InvokeCommandAction代表Loaded事件。