序列化Observable Collection时出错

5

我有一个可观察的集合,我正在尝试将其序列化到磁盘。收到的错误是:

 Type 'VisuallySpeaking.Data.GrammarList' with data contract name
 'GrammarList:http://schemas.datacontract.org/2004/07/VisuallySpeaking.Data'
 is not expected. Consider using a DataContractResolver or add any
 types not known statically to the list of known types - for example,
 by using the KnownTypeAttribute attribute or by adding them to the
 list of known types passed to
 DataContractSerializer."}  System.Exception
 {System.Runtime.Serialization.SerializationException}

这是我的数据对象:
namespace VisuallySpeaking.Data
{

    [CollectionDataContract]
    public class GrammarList : ObservableCollection<GrammarDataObject>
{
    public GrammarList() : base()
    {
        Add(new GrammarDataObject("My Name", "My name is","Assets/SampleAssets/MyName.png"));
        Add(new GrammarDataObject("Where is", "Where is",""));
        Add(new GrammarDataObject("Dog", "I have a dog","/Assets/SampleAssets/westie.jpg"));
    }
  }

  [DataContract]
  public class GrammarDataObject :  VisuallySpeaking.Common.BindableBase
  {
      private string _Name;
      private string _SpeakingText;
      private string _ImagePath;


      public GrammarDataObject(string Name, string SpeakingText, string ImagePath)
      {
          this.Name = Name;
          this.SpeakingText = SpeakingText;
          this.ImagePath = ImagePath;
      }

      [DataMember]
      public string Name
      {
          get { return _Name; }
          set
          {
              if (this._Name != value)
              {
                  this._Name = value;
                  this.OnPropertyChanged("Name");
              }
          }
      }

      [DataMember]
      public string SpeakingText
      {
          get { return _SpeakingText; }
          set
          {
              if (this._SpeakingText != value)
              {
                  this._SpeakingText = value;
                  this.OnPropertyChanged("SpeakingText");
              }
          }
      }

      [DataMember]
      public string ImagePath
      {
          get { return _ImagePath; }
          set
          {
              if (this._ImagePath != value)
              {
                  this._ImagePath = value;
                  this.OnPropertyChanged("ImagePath");
              }
          }
      }
  }

根据Fresh的评论,我也在这里添加了BindableBase。
namespace VisuallySpeaking.Common
{
    /// <summary>
    /// Implementation of <see cref="INotifyPropertyChanged"/> to simplify models.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    [DataContract(IsReference = true)]
    public abstract class BindableBase : INotifyPropertyChanged
    {
        /// <summary>
        /// Multicast event for property change notifications.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Checks if a property already matches a desired value.  Sets the property and
        /// notifies listeners only when necessary.
        /// </summary>
        /// <typeparam name="T">Type of the property.</typeparam>
        /// <param name="storage">Reference to a property with both getter and setter.</param>
        /// <param name="value">Desired value for the property.</param>
        /// <param name="propertyName">Name of the property used to notify listeners.  This
        /// value is optional and can be provided automatically when invoked from compilers that
        /// support CallerMemberName.</param>
        /// <returns>True if the value was changed, false if the existing value matched the
        /// desired value.</returns>
        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
        {
            if (object.Equals(storage, value)) return false;

            storage = value;
            this.OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Notifies listeners that a property value has changed.
        /// </summary>
        /// <param name="propertyName">Name of the property used to notify listeners.  This
        /// value is optional and can be provided automatically when invoked from compilers
        /// that support <see cref="CallerMemberNameAttribute"/>.</param>
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var eventHandler = this.PropertyChanged;
            if (eventHandler != null)
            {
                eventHandler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

我认为我不知道如何解决,但是我已经错误地标记了我的GrammarList类。 更新: 按照错误信息(当然),我添加了KnowTypeAttribute,它似乎起作用了:
[CollectionDataContract(Name = "GrammarList"),KnownType(typeof(GrammarList))]
public class GrammarList : ObservableCollection<GrammarDataObject>

再次感谢Fresh帮助我更新了CollectionDataContract,将Name更改为“GrammarList”,但是当我从磁盘重新加载XML文件时出现了问题。我收到以下错误消息:
期望命名空间为'http://schemas.datacontract.org/2004/07/VisuallySpeaking.Data'的元素'GrammarList'...遇到具有名称'GrammarDataObject'、命名空间为'http://schemas.datacontract.org/2004/07/VisuallySpeaking.Data'的'Element'。
序列化的XML代码如下:
<?xml version="1.0"?>    
<GrammarDataObject xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/VisuallySpeaking.Data" i:type="GrammarList">        
    <GrammarDataObject xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">    
         <ImagePath>Assets/SampleAssets/MyName.png</ImagePath>    
         <Name>My Name</Name>    
         <SpeakingText>My name is</SpeakingText>    
    </GrammarDataObject>


    <GrammarDataObject xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i3">    
        <ImagePath/>  
        <Name>Where is</Name>    
        <SpeakingText>Where is</SpeakingText>    
     </GrammarDataObject>


    <GrammarDataObject xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i4">    
        <ImagePath>/Assets/SampleAssets/westie.jpg</ImagePath>    
        <Name>Dog</Name>    
        <SpeakingText>I have a dog</SpeakingText>    
    </GrammarDataObject>    
</GrammarDataObject>

为什么XML的外部标签没有列为“GrammarList”?我认为这就是反序列化器正在寻找的内容。当我手动编辑序列化后的xml以将GrammarList放置为外部标签时,它可以正确地反序列化。我确信我又错过了什么!更新:在序列化时,我的代码如下:
DataContractSerializer serializer = new DataContractSerializer(typeof(GrammarDataObject));

我将其更改为将内容序列化为GrammarList,问题得到了解决!!!感谢Fresh的帮助。
DataContractSerializer serializer = new DataContractSerializer(typeof(GrammarList));

1
当你能够时,请将Fresh的答案标记为被接受的答案并给他点赞。这样,像我这样的读者就会立刻知道你的问题已经解决了! ;) 这是在SO上的正确做法。我还建议你查看我们的帮助部分:http://stackoverflow.com/help 顺便说一下,你的问题表述得非常清晰。 - ForceMagic
1个回答

1

从XML输出来看,当反序列化时,集合的名称似乎丢失了。

尝试设置CollectionDataContract的Name属性,例如:

[CollectionDataContract(Name="GrammarList"),KnownType(typeof(GrammarList))]
public class GrammarList : ObservableCollection<GrammarDataObject>

我实际上标记了BindableBase。我不确定如何在这里放置代码,因此我将使用BindableBase代码更新原始帖子。 - user1558885
我尝试添加 [field:NonSerialized] 属性,但它在 winrt 中无法识别(我找不到它对应的内容)。 - user1558885
谢谢Fresh - 我添加了Name属性,但在重新生成方面没有任何变化。行为很奇怪...如果你可以序列化,那么应该能以完全相同的方式反序列化。 - user1558885
当您添加了“Name”属性时,序列化的XML是否与之前完全相同?我希望在那里看到一个“Name”属性。此外,您是如何执行序列化的,即您的确切方法调用是什么? - Ben Smith
啊哈!我找到问题了。我序列化并传递了一个typeof(GrammarDataObject)。因此它将其放置在外部标签上。我会更新帖子。感谢你的帮助,Fresh. :) - user1558885
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接