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 文件时,我收到以下错误:

Aggregate Exception

这是加载文件的方法:

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