我正在尝试编写家庭自动化软件。目前我有以下课程:
- 首页
-Room
-Device
-WindowShutter(继承自设备)
-Sensor(从设备继承)
目前,包含Rooms(包含设备)的Home对象以XML格式保存。
public static async void SaveHome(Home MyHome)
{
MemoryStream _MemoryStream = new MemoryStream();
DataContractSerializer Serializer = new DataContractSerializer(typeof(Home));
Serializer.WriteObject(_MemoryStream, MyHome);
StorageFile _File = await ApplicationData.Current.LocalFolder.CreateFileAsync("Home2.bin", CreationCollisionOption.ReplaceExisting);
using (Stream fileStream = await _File.OpenStreamForWriteAsync())
{
_MemoryStream.Seek(0, SeekOrigin.Begin);
await _MemoryStream.CopyToAsync(fileStream);
await fileStream.FlushAsync();
fileStream.Dispose();
}
}
由于设备类型不同,保存的文件如下所示:
<Home xmlns="http://schemas.datacontract.org/2004/07/CSRedAlert.Core.Classes" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>My Home</Name>
<Rooms>
<Room><Color/><Devices><Device><I2C_Slave_Address>64</I2C_Slave_Address><Id>0</Id><ImagePath i:nil="true"/><Name>My Device</Name><Pin>D0</Pin></Device>
<Device i:type="WindowShutter"><I2C_Slave_Address>64</I2C_Slave_Address><Id>1</Id><ImagePath i:nil="true"/><Name>My Window Shutter</Name><Pin>D0</Pin><SecondaryPin>D1</SecondaryPin></Device>
<Device i:type="Sensor"><I2C_Slave_Address>64</I2C_Slave_Address><Id>2</Id><ImagePath i:nil="true"/><Name>My Sensor</Name><Pin>A2</Pin></Device></Devices><I2C_SlaveAdress>64</I2C_SlaveAdress>
<Name>Room</Name></Room></Rooms></Home>
问题是,只要我第二次启动程序并加载Home2.bin文件,我就会收到以下错误:
这是加载文件的方法:
public static async Task<Home> LoadHome()
{
StorageFolder _Folder = ApplicationData.Current.LocalFolder;
StorageFile _File;
try
{
_File = await _Folder.GetFileAsync("Home2.bin");
Stream stream = await _File.OpenStreamForReadAsync();
DataContractSerializer Serializer = new DataContractSerializer(typeof(Home));
return (Home)Serializer.ReadObject(stream);
}
catch (FileNotFoundException)
{
return new Home();
}
}
我发现,当我从Home2.bin文件中的设备元素中删除i:type属性时,将加载该文件。但是当我删除它时,设备会丢失它们的类型,并且不会按预期工作。
你知道如何解决这个问题吗?
答案 0 :(得分:0)
您看到该异常的原因是DataContractSerializer
要求在序列化期间遇到的所有类型都可以通过反射静态发现 。如果遇到意外类型 - 包括多态类型的子类 - 它会抛出异常。
对于多态类型,您可以使用[KnownTypeAttribute]
通知序列化程序预期的子类型。完成后,"{http://www.w3.org/2001/XMLSchema-instance}type"
属性将指示已序列化的实际合同的名称。
因此,您的课程应该类似于:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/CSRedAlert.Core.Classes")]
[KnownType(typeof(WindowShutter))]
[KnownType(typeof(Sensor))]
public class Device
{
[DataMember]
public int I2C_Slave_Address { get; set; }
[DataMember]
public int Id { get; set; }
[DataMember]
public string ImagePath { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Pin { get; set; }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/CSRedAlert.Core.Classes")]
public class WindowShutter : Device
{
[DataMember]
public string SecondaryPin { get; set; }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/CSRedAlert.Core.Classes")]
public class Sensor : Device
{
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/CSRedAlert.Core.Classes")]
public class Home
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<Room> Rooms { get; set; }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/CSRedAlert.Core.Classes")]
public class Room
{
[DataMember]
public string Color { get; set; }
[DataMember]
public List<Device> Devices { get; set; }
[DataMember]
public int I2C_SlaveAdress { get; set; }
[DataMember]
public string Name { get; set; }
}
有关详情,请参阅Data Contract Known Types和Known Types。