c# 加载序列化文件失败 - Class 属性 i:type
c# Loading of serialized file fails - Class property i:type
我正在尝试编写一个家庭自动化软件。目前我有以下 类:
-首页
-房间
-设备
-WindowShutter(从设备继承)
-传感器(从设备继承)
当前,包含房间(包含设备)的家庭对象保存在 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 属性 时,该文件将被加载。但是当我删除它时,设备将丢失它们的类型并且无法按预期工作。
你知道如何解决这个问题吗?
您看到该异常的原因是 DataContractSerializer
要求它在序列化过程中遇到的所有类型都可以通过反射提前 静态发现。如果遇到意外类型——包括多态类型的子类——它会抛出异常。
对于多态类型,您可以使用 [KnownTypeAttribute]
. Once that is done, the "{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 and Known Types。
我正在尝试编写一个家庭自动化软件。目前我有以下 类:
-首页
-房间
-设备
-WindowShutter(从设备继承)
-传感器(从设备继承)
当前,包含房间(包含设备)的家庭对象保存在 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 属性 时,该文件将被加载。但是当我删除它时,设备将丢失它们的类型并且无法按预期工作。
你知道如何解决这个问题吗?
您看到该异常的原因是 DataContractSerializer
要求它在序列化过程中遇到的所有类型都可以通过反射提前 静态发现。如果遇到意外类型——包括多态类型的子类——它会抛出异常。
对于多态类型,您可以使用 [KnownTypeAttribute]
. Once that is done, the "{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 and Known Types。