Невозможно xml сериализовать пользовательский объект - PullRequest
0 голосов
/ 10 мая 2011

Я создал действительно простой элемент управления, который содержит список элементов управления параметрами фильтра почти так же, как список имеет список элементов списка.

У меня возникли некоторые проблемы, пытаясь заставить его сериализоваться в viewstate, так как сериализатор, кажется, пытается сериализовать свойства базового класса, и в основном я получаю ошибки вроде - не могу сериализовать свойство "page" Что вы думаете моя проблема?

Код:

[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 ]

1 голос
/ 10 мая 2011

Прежде всего, вы должны разделить свои управляющие и сериализуемые данные. Во-вторых, .net Framework содержит несколько типов сериализации:

  1. Утилиты сериализации от System.Runtime.Serialization ([BinaryFormatter][1] и [SoapFormatter][2]). Для обоих этих способов требуется [SerializationAttribute][3] для вашего класса или реализация интерфейса [ISerializable][4] (если вам нужен более гибкий способ управления процессом сериализации). Эти сериализаторы сериализуют все приватные поля для текущего класса и всех его потомков, если эти поля не отмечены [NonSerialializedAttribute][5].

Примечание: эта сериализация используется во время удаленного взаимодействия .net.

  1. XML-сериализация с классом [XmlSerializer][6]. В этом случае ваш класс должен иметь конструктор без параметров, и этот сериализатор сериализует все открытые свойства чтения / записи для текущего класса и всех потомков, которые не помечаются [XmlIgnoreAttribute][7].

  2. [DataContractSerializer][8]. Этот сериализатор требует, чтобы ваша сущность была помечена [DataContractAttribute][9], а все свойства должны быть помечены [DataMemberAttribute][10]. Также этот сериализатор может сериализовать классы, сериализуемые двумя предыдущими способами.

В общем, очень плохая практика - пытаться сериализовать пользовательский контроль, потому что он определенно содержит несериализуемые поля (которые не отмечены 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);
0 голосов
/ 26 июня 2011

Очевидно, что вы не можете сериализовать тип, который наследует несериализуемый тип, даже если вы не хотите сериализовать несериализуемые свойства вашего производного типа.

Я думаю, что это должно быть классифицировано как ошибка, так как основная задача интерфейсов, таких как ISerializable, заключается в том, чтобы точно указать, что именно вы вводите для сериализации, вручную реализуя метод, который обрабатывает сериализацию.

В любом случае решение моего конкретного сценария состояло в том, чтобы вообще не беспокоить сериализацию и просто сохранить интересующую информацию в viewstate, которая затем использовалась бы в обратных передачах для восстановления элементов управления в том же состоянии, готовом для обратной передачи на основе страниц. события, которые должны произойти.

Жаль, что это лучше не документировано где-то, потому что, хотя Microsoft действительно документирует методы SaveViewState и LoadViewState жизненного цикла страницы, они очень расплывчаты относительно того, как эти события могут быть использованы, я предполагаю, что они надеются, что кто-то в сообществе может привести пример .

Я бы опубликовал свой код, но это неприятный хак, чтобы все заработало, поэтому я не думаю, что это должен быть основной код MSDN.

Хорошо для небольшого внутреннего приложения:)

0 голосов
/ 10 мая 2011

Вы должны взглянуть на эту ссылку для XML-сериализации

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

с учетом ваших комментариев.Я снова искал, и теперь я думаю, что вы забыли добавить этот код в вашу функцию GetObjectData().

base.GetObjectData(si,context);
0 голосов
/ 10 мая 2011

Вы не можете сериализовать ваш объект, потому что он содержит объекты, которые не сериализуются.Элементы управления ASP.NET (например, CheckBox и Label) не сериализуемы.

Вместо этого вы должны создать список объектов, который содержит только те данные, которые вам действительно нужны, что, безусловно, будет иметь значение boolean и string.

Затем необходимо повторно создавать элементы управления из этого состояния при каждом запросе Post, но я не знаю другого способа.

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

РЕДАКТИРОВАТЬ:

Вы можете поставить атрибут [NonSerialized] над членами, которые вы не хотите сериализовать.

...