?
Solved

Serialization and Event Publishers

Posted on 2005-03-01
9
Medium Priority
?
244 Views
Last Modified: 2010-04-16
Hi

I have an application consisting of Form A and Class B. Class B stores a set of values that I want to save to file, and is therefore Serializable. However, I also added an event to it so that when one of the values changed, a subscriber (in this case Form A) was notified, and could refresh itself.

What actually happened was that when I attempted to write Class B to a filestream, it failed with a 'NonSerializable object' error - the object in question was the form.

Is this because I've added the form to Class B as a subscriber, and therefore .NET assumes it must also serialize the form? Assuming it is, what is the 'best practice' for dealing with this situation, bearing in mind that I can't mark an event as NonSerializable? Encapsulate Class B within another class that publishes the event? (I was hoping to avoid this, as it takes the responsibility of its own objects away from Class B, and means every change to variables within Class B will have to go through this wrapper).

Many thanks
Gerry
0
Comment
Question by:gamesmeister
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
9 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 13428111
Please show your code.
0
 
LVL 4

Author Comment

by:gamesmeister
ID: 13429507
Code as follows (names changed to protect the innocent). When I try to serialize an instance of MyClass, I get the following error
********************************************************************
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll

Additional information: The type MyForm in Assembly MyExe, Version=1.0.1886.24124, Culture=neutral, PublicKeyToken=null is not marked as serializable.
**********************************************************************

public class MyForm
{
      public MyForm()
      {
            MyClass mc = new MyClass();
            mc.ArrayListChanged +=new EventHandler(mc_ArrayListChanged);
      }
      

      private void mc_ArrayListChanged(object sender, EventArgs e)
      {
            //update list view on Form
      }
}


[Serializable]
public class MyProject
{
      private ArrayList myArray;
      protected event EventHandler arrayListChanged;

      public MyProject()
      {
            myArray = new ArrayList();
      }

      public event EventHandler ArrayListChanged
      {
            add      {arrayListChanged += value;}
            remove {arrayListChanged -= value;}
      }

      public void AddString(string myString)
      {
            myArray.Add(myString);
            if (arrayListChanged != null)
            {
                  OnArrayListChanged(new EventArgs());
            }
      }

      protected void OnArrayListChanged(System.EventArgs e)
      {
            arrayListChanged (this, e);
      }
}
0
 
LVL 4

Author Comment

by:gamesmeister
ID: 13429549
Sorry, the class should be called MyClass, not MyProject
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 48

Expert Comment

by:AlexFM
ID: 13429604
Where is serialization code? It looks like you are trying to serialize MyForm and not MyClass.
0
 
LVL 4

Author Comment

by:gamesmeister
ID: 13430157
The Serialization code is in a class library, called from MyForm. It receives an object and a path, and saves it as per the following. The object I'm passing as 'data' is the instance of MyClass (mc). One other thing - this all worked fine until I added the event handler to MyClass

public class BinaryPersistence : IPersistence
{
      private object storedData;
      private Stream stream;
      
      public BinaryPersistence()
      {
      }

      public void StoreFile(object data, string path)
      {
            if (data.Equals(null))
            {
                  throw (new ArgumentNullException("data", "No data passed to store"));
            }
            else
            {
                  if (path.Equals(null))
                  {
                        throw (new ArgumentNullException("path", "Filename cannot be null"));
                  }
            }
      
            stream = new FileStream(path,FileMode.Create,FileAccess.Write);
            StoreStream(data);
      }
      
      private void StoreStream(object data)
      {
            IFormatter f = new BinaryFormatter();
            f.Serialize(stream, data);
            stream.Close();
      }

}
0
 
LVL 4

Author Comment

by:gamesmeister
ID: 13447451
From the lack of response, can I assume that it's normally perfectly ok to add Event Handlers to a serializable class, and that there's something else wrong here?
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 13447477
Currently I have no answer, I will try to make small test later.
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 2000 total points
ID: 13447745
I reproduced this situation and found that it happened when event is subscribed. After commenting of line
mc.ArrayListChanged +=new EventHandler(mc_ArrayListChanged);
serialization succeeds. I don't know why this happens, but there is a way to solve this: unsubscribe from event before serialization and subscribe again after serialization. This is my small test, see button1_Click function.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Test
{
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button button1;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        MyClass mc;
        EventHandler eh;

        public Form1()
        {
            InitializeComponent();

            mc = new MyClass();
            eh = new EventHandler(mc_ArrayListChanged);
            mc.ArrayListChanged += eh;
        }

        private void mc_ArrayListChanged(object sender, EventArgs e)
        {
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            mc.ArrayListChanged -= eh;    //  unsubscribe

            FileStream stream = new FileStream("C:\\test.bin", FileMode.Create,FileAccess.Write);
            StoreStream(mc, stream);

            mc.ArrayListChanged += eh;    // subscribe again
        }

        private void StoreStream(object data, FileStream stream)
        {
            IFormatter f = new BinaryFormatter();
            f.Serialize(stream, data);
            stream.Close();
        }


        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // button1
            //
            this.button1.Location = new System.Drawing.Point(80, 104);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(120, 32);
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }
    }
}

0
 
LVL 4

Author Comment

by:gamesmeister
ID: 13475679
That's an excellent workaround, thanks Alex
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…
Suggested Courses

741 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question