无法xml序列化自定义对象

时间:2011-05-10 09:27:43

标签: c# asp.net serialization xml-serialization

我创建了一个非常简单的控件,其中包含一个过滤器选项控件列表,其方式与列表框中包含列表项列表的方式非常相似。

由于序列化程序似乎正在尝试序列化基类属性并且基本上我最终会出现类似错误 - 无法序列化属性“页面”,我有一些麻烦要让它序列化到viewstate状态你觉得怎么样?是我的问题?

守则:

[Serializable]
public class FilterOption : Control, ISerializable
{
    public event EventHandler Checkchanged;

    CheckBox _chk = new CheckBox();
    Label _lbl = new Label();

    public string Text
    {
        get { return _lbl.Text; }
        set { _lbl.Text = value; }
    }

    public bool Checked
    {
        get { return _chk.Checked; }
        set { _chk.Checked = value; }
    }

    public FilterOption()
    {
        Controls.Add(new LiteralControl("<li>"));
        _chk.AutoPostBack = true;
        _chk.CssClass = "checkbox";
        Controls.Add(_chk);
        Controls.Add(_lbl);
        _chk.CheckedChanged += new EventHandler(_chk_CheckedChanged);
        Controls.Add(new LiteralControl("</li>"));
    }

    public FilterOption(string Text, bool Checked)
    {
        Controls.Add(new LiteralControl("<li>"));
        _chk.CssClass = "checkbox";
        _lbl.Text = Text;
        _chk.Checked = Checked;
        Controls.Add(_chk);
        Controls.Add(_lbl);
        _chk.CheckedChanged += new EventHandler(_chk_CheckedChanged);
        Controls.Add(new LiteralControl("</li>"));
    }

    public FilterOption(SerializationInfo info, StreamingContext context)
    {
        Controls.Add(new LiteralControl("<li>"));
        _chk.CssClass = "checkbox";
        _lbl.Text = (string)info.GetValue("Text", typeof(string));
        _chk.Checked = (bool)info.GetValue("Text", typeof(bool));
        Controls.Add(_chk);
        Controls.Add(_lbl);
        _chk.CheckedChanged += new EventHandler(_chk_CheckedChanged);
        Controls.Add(new LiteralControl("</li>"));
    }

    void _chk_CheckedChanged(object sender, EventArgs e)
    {
        if (Checkchanged != null)
            Checkchanged(this, new EventArgs());
    }


    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if(info == null)
            throw new System.ArgumentNullException("info");

        info.AddValue("Text", _lbl.Text);
        info.AddValue("Checked", _chk.Checked);
    }
}

我只需要序列化添加到GetObjectData方法中的序列化信息的属性。

我正在使用以下代码执行序列化...

List<FilterOption> options = new List<FilterOption>();

    ... add some items to the collection ... 

StringWriter writer = new StringWriter();
XmlSerializer ser = new XmlSerializer(typeof(List<FilterOption>));
ser.Serialize(writer, options);
ViewState["Options"] = writer.ToString();

哦,是的...我忘了添加......我从这里得到了信息...... http://msdn.microsoft.com/en-us/library/ms973893.aspx

(如果重要)

...

Thx Wardy

4 个答案:

答案 0 :(得分:1)

首先,您应该拆分控件和可序列化数据。其次,.net框架包含几种序列化类型:

  1. 来自System.Runtime.Serialization[BinaryFormatter][1][SoapFormatter][2])的序列化实用程序。这两个版本都需要[SerializationAttribute][3]用于您的类或实现[ISerializable][4]接口(如果您需要更灵活的方式来控制序列化过程)。这些序列化程序序列化当前类的所有私有字段及其所有后代(如果该字段未标记为[NonSerialializedAttribute][5])。
  2. 注意:此序列化在.net远程处理期间使用。

    1. 使用[XmlSerializer][6]类进行Xml序列化。在这种情况下,您的类应该具有无参数构造函数,并且此序列化程序序列化当前类的所有公共读/写属性以及未标记[XmlIgnoreAttribute][7]的所有后代。

    2. [DataContractSerializer][8]。此序列化程序要求您应将实体标记为[DataContractAttribute][9],并且所有属性都应标记为[DataMemberAttribute][10]。此序列化程序还可以通过以前的两种方式序列化可序列化的类。

    3. 一般来说,尝试序列化用户控件是非常糟糕的做法,因为它肯定会包含不可序列化的字段(未标记为NonSerializedAttribute)。因此,您肯定会在运行时收到错误消息。

      最简单的方法(从设计的角度来看更合适)是将可序列化的数据分离到单独的类中,并选择正确的序列化技术。

      即。如果你想使用Xml序列化,你应该为你的类创建无参数构造函数并使用读/写属性:

      public class FilterOption
      {
        public FilterOption() {}
      
        public string MyLabel{get;set;}
        public bool IsChecked{get;set;}
      }
      

      现在您可以使用以前的代码:

      var options = new List<FilterOption>
      {
          new FilterOption {MyLabel = "label", IsChecked = false},
          new FilterOption {MyLabel = "label2", IsChecked = true}
      };
      StringWriter writer = new StringWriter();
      XmlSerializer ser = new XmlSerializer(typeof(List<FilterOption>));
      ser.Serialize(writer, options);
      

答案 1 :(得分:0)

您无法序列化对象,因为它包含不可序列化的对象。 ASP.NET控件(如CheckBoxLabel)不可序列化。

你应该创建一个对象列表,它只包含你真正需要的数据,肯定是boolean值和string

然后,您必须在每个Post请求中从此状态重新创建控件,但我没有其他方式。

[Serializable]
public class FilterOption
{
  public string MyLabel{get;set;}
  public bool IsChecked{get;set}
}

修改

您可以将属性[NonSerialized]放在您不希望序列化的成员之上。

答案 2 :(得分:0)

您应该查看此链接,了解XML序列化

http://msdn.microsoft.com/en-us/library/ms950721.aspx

考虑你的意见。我再次搜索,现在我认为您忘记在GetObjectData()函数中添加此代码。

base.GetObjectData(si,context);

答案 3 :(得分:0)

显然,即使您不希望序列化派生类型的非可序列化属性,也无法序列化继承非序列化类型的类型。

我认为这应该被归类为一个bug,因为像ISerializable这样的接口是指通过手动实现处理序列化的方法来准确指定序列化的内容。

在任何情况下,我的特定场景的解决方案是根本不打扰序列化,只需将感兴趣的信息保存到viewstate中,然后在回发时重复使用,以便在完全相同的状态下重建控件,为基于页面的回发做好准备事件发生。

遗憾的是,这并没有更好地记录在某处,因为虽然microsoft确实记录了页面生命周期的SaveViewState和LoadViewState方法,但他们对如何使用这些事件非常模糊,我猜他们希望社区中的某个人可能提供一个例子

我会发布我的代码,但它是一个令人讨厌的黑客,以使一切工作,所以我不应该是主流的msdn代码。

确实是一个小型内部应用程序:)