是否无法从默认构造函数反序列化为 'this'?
Is it not possible to deserialize to 'this' from default constructor?
情况:
我有一个绑定到设置视图的 ViewModel,用户应该在其中输入许多个性化设置,并且应该能够将它们保存为预设并加载它们。为此,ViewModel 包含预设数据模型的集合,这些模型本身包含不同的属性、class 对象等。
计划是通过xml 序列化和反序列化整个ViewModel 来实现保存所有预设。
代码/问题
我从 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()
,反序列化器在永无止境的循环中调用自己,导致计算器溢出错误。
所以,最简单的解决方案应该是使用另一个带参数的构造函数,我在这里调用InitializePresetsFromFile()
,对吧?这里的问题是ViewModelclass是在对应View的xaml中直接实例化的:
<UserControl.Resources>
<ResourceDictionary>
<vm:LinearAxisColorPresetsViewModel x:Key="vm" />
</ResourceDictionary>
</UserControl.Resources>
This posts 第二个答案指出约定是,从 XAML 调用的构造函数应该是无参数的,我想坚持这一点。
问题:
问题只是如何根据最佳实践解决这个问题。由于这是我第一次尝试序列化和反序列化,我担心我在这里走错了路。我的感觉是只有数据模型 classes 应该被序列化。我的 ViewModel 包含两个这样的 classes 的 ObservableCollection,但是我想序列化完整的集合以及 ViewModel 中的其他属性,例如所选索引。
您确实已经到了必须决定如何继续的地步。你现在所做的是行不通的。 XML 序列化程序和 XAML 在这种情况下都使用默认构造函数。你不能让它在这里有两个用途。
我的建议是创建一个 class 来反映您用于反序列化 XML 文件的视图模型的属性。这个class只需要属性,仅此而已。
如果视图模型 class 实际上是静态的,您可以使用 a locator class 将其绑定到。
首先,您不应该在 class' 构造函数中调用 InitializePresetsFromFile
方法。构造函数必须尽可能快并且不应该引起副作用。在构造函数中读取文件是一种不好的做法:如果不访问文件系统,就无法创建 class 的实例。这意味着您的代码不可测试,容易出错(例如,您是否考虑过突然的 UnauthorizedAccessException
s?),而且速度很慢。
相反,创建一个 public 方法来反序列化文件中的数据。这将打破你的无限递归。
如何调用该方法?
- 您真的需要资源字典中的
LinearAxisColorPresetsViewModel
实例吗?如果没有,只需将反序列化实例分配给视图的 DataContext
属性。
- 如果确实需要,请在视图模型中创建一个
ICommand
,例如InitializeCommand
使用上述方法从文件初始化内部状态;在 app startup/view show-up 等上执行该命令。您可以使用例如InvokeCommandAction
用于 Loaded
事件。
情况:
我有一个绑定到设置视图的 ViewModel,用户应该在其中输入许多个性化设置,并且应该能够将它们保存为预设并加载它们。为此,ViewModel 包含预设数据模型的集合,这些模型本身包含不同的属性、class 对象等。 计划是通过xml 序列化和反序列化整个ViewModel 来实现保存所有预设。
代码/问题
我从 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()
,反序列化器在永无止境的循环中调用自己,导致计算器溢出错误。
所以,最简单的解决方案应该是使用另一个带参数的构造函数,我在这里调用InitializePresetsFromFile()
,对吧?这里的问题是ViewModelclass是在对应View的xaml中直接实例化的:
<UserControl.Resources>
<ResourceDictionary>
<vm:LinearAxisColorPresetsViewModel x:Key="vm" />
</ResourceDictionary>
</UserControl.Resources>
This posts 第二个答案指出约定是,从 XAML 调用的构造函数应该是无参数的,我想坚持这一点。
问题:
问题只是如何根据最佳实践解决这个问题。由于这是我第一次尝试序列化和反序列化,我担心我在这里走错了路。我的感觉是只有数据模型 classes 应该被序列化。我的 ViewModel 包含两个这样的 classes 的 ObservableCollection,但是我想序列化完整的集合以及 ViewModel 中的其他属性,例如所选索引。
您确实已经到了必须决定如何继续的地步。你现在所做的是行不通的。 XML 序列化程序和 XAML 在这种情况下都使用默认构造函数。你不能让它在这里有两个用途。
我的建议是创建一个 class 来反映您用于反序列化 XML 文件的视图模型的属性。这个class只需要属性,仅此而已。
如果视图模型 class 实际上是静态的,您可以使用 a locator class 将其绑定到。
首先,您不应该在 class' 构造函数中调用 InitializePresetsFromFile
方法。构造函数必须尽可能快并且不应该引起副作用。在构造函数中读取文件是一种不好的做法:如果不访问文件系统,就无法创建 class 的实例。这意味着您的代码不可测试,容易出错(例如,您是否考虑过突然的 UnauthorizedAccessException
s?),而且速度很慢。
相反,创建一个 public 方法来反序列化文件中的数据。这将打破你的无限递归。
如何调用该方法?
- 您真的需要资源字典中的
LinearAxisColorPresetsViewModel
实例吗?如果没有,只需将反序列化实例分配给视图的DataContext
属性。 - 如果确实需要,请在视图模型中创建一个
ICommand
,例如InitializeCommand
使用上述方法从文件初始化内部状态;在 app startup/view show-up 等上执行该命令。您可以使用例如InvokeCommandAction
用于Loaded
事件。