15

In Windows Forms, .NET Framework 4.0, I am trying to Serialize an instance of a class I wrote.

The class is marked as Serializable, but the form that uses the class (obviously) is not.

I do not want to Serialize an instance of the form. I want to Serialize the data I have in my class.

Everything in my class is marked as Serializable, so why am I still getting the SerializationException?

SerializationException.png

(Click >> HERE << to open image full-size in a new window)

Update:

Here is my BrazierCuttoff class and related parts:

[Serializable()]
public class BrazierCuttoff : IEquatable<BrazierCuttoff> {
  private int qty;
  private int[] joint, pass, shift;
  private float mult;
  private BrazierPay a, b, c, d, e;
  public event EventHandler BrazierCuttoffChanged;
  public const int MAXIMUMSMALLQUANTITY = 20;
  EnumeratedLevel[,] eLvArray;
  /// <summary>
  /// Gets or Sets the Brazier Matrix values
  /// </summary>
  /// <param name="passRatioIndex">0=100%,1=95,2=90,3=85,4=80,5=75,6=70,7=65</param>
  /// <param name="minJointIndex">0=900,1=1200,2=1400,3=1600,4=1800,5=2000,6=2100,=2200</param>
  /// <returns>Brazier Matrix value</returns>
  public EnumeratedLevel this[int passRatioIndex, int minJointIndex] {
    get { return eLvArray[passRatioIndex, minJointIndex]; }
    set { eLvArray[passRatioIndex, minJointIndex] = value; }
  }
  /// <summary>
  /// Initializes a new Form Values object using default values
  /// </summary>
  public BrazierCuttoff() {
    A = new BrazierPay(5.0f);
    B = new BrazierPay(4.0f);
    C = new BrazierPay(3.0f);
    D = new BrazierPay(2.0f);
    E = new BrazierPay(1.0f);
    NA = new BrazierPay(0.0f);
    ShiftMinimum = new int[] { 12, 12, 12 };
    PassRatio = new int[] { 100, 95, 90, 85, 80, 75, 70, 65 };
    JointMinimum = new int[] { 900, 1200, 1400, 1600, 1800, 2000, 2100, 2200 };
    eLvArray = new EnumeratedLevel[8, 8];
    EnumeratedLevel level = EnumeratedLevel.NA_Silver;
    for (int y = 0; y < 8; y++) {
      for (int x = 0; x < 8; x++) {
        switch (y) {
          case 0: level = (x < 2) ? EnumeratedLevel.B_Blue : EnumeratedLevel.A_Violet; break;
          case 1: level = (x == 0) ? EnumeratedLevel.C_Green : (x < 3) ? EnumeratedLevel.B_Blue : EnumeratedLevel.A_Violet; break;
          case 2: level = (x < 2) ? EnumeratedLevel.C_Green : (x < 5) ? EnumeratedLevel.B_Blue : EnumeratedLevel.A_Violet; break;
          case 3: level = (x == 0) ? EnumeratedLevel.D_Yellow : (x < 4) ? EnumeratedLevel.C_Green : (x < 6) ? EnumeratedLevel.B_Blue : EnumeratedLevel.A_Violet; break;
          case 4: level = (x < 2) ? EnumeratedLevel.D_Yellow : (x < 5) ? EnumeratedLevel.C_Green : EnumeratedLevel.B_Blue; break;
          case 5: level = (x == 0) ? EnumeratedLevel.E_Orange : (x < 3) ? EnumeratedLevel.D_Yellow : (x < 6) ? EnumeratedLevel.C_Green : EnumeratedLevel.B_Blue; break;
          case 6: level = (x < 2) ? EnumeratedLevel.E_Orange : (x < 5) ? EnumeratedLevel.D_Yellow : EnumeratedLevel.C_Green; break;
          default: level = (x == 0) ? EnumeratedLevel.NA_Silver : (x < 5) ? EnumeratedLevel.E_Orange : EnumeratedLevel.D_Yellow; break;
        }
        eLvArray[x, y] = level;
      }
    }
  }

  private void broadcast() {
    if (BrazierCuttoffChanged != null) {
      BrazierCuttoffChanged(this, new EventArgs());
    }
  }
  /// <summary>
  /// Gets or Sets the A Pay Level data
  /// </summary>
  public BrazierPay A { get { return a; } set { if (a != value) { a = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the B Pay Level data
  /// </summary>
  public BrazierPay B { get { return b; } set { if (b != value) { b = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the C Pay Level data
  /// </summary>
  public BrazierPay C { get { return c; } set { if (c != value) { c = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the D Pay Level data
  /// </summary>
  public BrazierPay D { get { return d; } set { if (d != value) { d = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the E Pay Level data
  /// </summary>
  public BrazierPay E { get { return e; } set { if (e != value) { e = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the N/A Pay Level data
  /// </summary>
  public BrazierPay NA { get; private set; }

  public void Refresh() {
    const float delta = 0.01f;
    while (A.Dirty || B.Dirty || C.Dirty || D.Dirty || E.Dirty) {
      if (A.Dirty) {
        if (A.Value <= B.Value) B.Value = A.Value - delta;
        A.Dirty = false;
      } else if (B.Dirty) {
        if (B.Value <= C.Value) C.Value = B.Value - delta;
        if (A.Value <= B.Value) A.Value = B.Value + delta;
        B.Dirty = false;
      } else if (C.Dirty) {
        if (C.Value <= D.Value) D.Value = C.Value - delta;
        if (B.Value <= C.Value) B.Value = C.Value + delta;
        C.Dirty = false;
      } else if (D.Dirty) {
        if (D.Value <= E.Value) E.Value = D.Value - delta;
        if (C.Value <= D.Value) C.Value = D.Value + delta;
        D.Dirty = false;
      } else if (E.Dirty) {
        if (D.Value <= E.Value) D.Value = E.Value + delta;
        E.Dirty = false;
      }
    }
  }
  /// <summary>
  /// Gets the minimum Average Joints requirement
  /// </summary>
  public int AverageJoints { get { return JointMinimum[0]; } }
  /// <summary>
  /// Gets the minimum Chamber Pass Ratio requirement
  /// </summary>
  public int FirstTimePassRate { get { return PassRatio[PassRatio.Length - 1]; } }
  /// <summary>
  /// Gets or sets the Minimum Average Joints requirements (Range: 0 @ 900 to 7 @ 2200)
  /// </summary>
  public int[] JointMinimum { get { return joint; } set { if (joint != value) { joint = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the Chamber Pass Ratio levels (Range: 0 @ 100% to 7 @ 65%)
  /// </summary>
  public int[] PassRatio { get { return pass; } set { if (pass != value) { pass = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the Integral Array of minimum shifts required to qualify for a bonus
  /// </summary>
  public int[] ShiftMinimum { get { return shift; } set { if (shift != value) { shift = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the Small Workorder Multiplier (1 is default/disable)
  /// </summary>
  public float SmallWoMulti { get { return mult; } set { if (mult != value) { mult = value; broadcast(); } } }
  /// <summary>
  /// Gets or Sets the Small Workorder Quantity value (0 is disable)
  /// </summary>
  public int SmallWoQty { get { return qty; } set { if (qty != value) { qty = value; broadcast(); } } }

  #region IEquatable<BrazierCuttoff> Members

  public bool Equals(BrazierCuttoff other) {
    if (other != null) {
      if ((A == other.A) && (B == other.B) && (C == other.C) && (D == other.D) && (E == other.E) && (NA == other.NA)) {
        if ((ShiftMinimum == other.ShiftMinimum) && (PassRatio == other.PassRatio) && (JointMinimum == other.JointMinimum)) {
          return (eLvArray == other.eLvArray);
        }
      }
    }
    return false;
  }

  #endregion

}

This is the BrazierPay object that is used in the class above:

[Serializable()]
public class BrazierPay {
  float pay;
  public BrazierPay(float payLevel) {
    Dirty = false;
    pay = payLevel;
  }
  public float Value {
    get { return pay; }
    set {
      if (pay != value) {
        Dirty = true;
        pay = value;
      }
    }
  }
  public bool Dirty { get; set; }
  public string DollarValue { get { return string.Format("{0:C}", pay); } }
  public string Formatted { get { return string.Format("{0:F}", pay); } }
  public override string ToString() { return Formatted; }
}

I even marked this enumerated type as Serializable (though, it should not need it):

[Serializable()]
public enum EnumeratedLevel {
  NA_Silver = Clicker.NA_Silver, // Color.Silver
  E_Orange = Clicker.E_Orange, // Color.Orange
  D_Yellow = Clicker.D_Yellow, // Color.Yellow
  C_Green = Clicker.C_Green, // Color.Lime
  B_Blue = Clicker.B_Blue, // Color.DodgerBlue
  A_Violet = Clicker.A_Violet, // Color.Violet
}
  • 1
    Looks like you are trying to serialize something that inherits from `Form`? And the half of the partial definition you've provided isn't marked as `Serializable`. You will find it difficult trying to serialize stuff that inherits from other stuff you have no control over, lots of things are not marked serializable and you won't be able to change that. `Form` is one such class. – Adam Houldsworth Jul 16 '12 at 15:49
  • 1
    The `BrazierCuttoff` class has an `EventHandler` to enable me to code for changes in the data. Could this be causing my problems? If so, how would I exclude the EventHandler from my class? My class should be posted shortly. –  Jul 16 '12 at 16:21

4 Answers4

24

Resolved

I needed to set a NonSerializedAttribute for the EventHandler.

The event delegate could not be serialized in the class (see Delegates and Serialization).

Marking the field as NonSerializedAttribute was as easy as it sounds.

From my code, I simply added this line:

[field:NonSerializedAttribute()]
public event EventHandler BrazierCuttoffChanged;
  • 2
    Well done for finding the answer, I was just about to post exactly this when I saw your comment on the event. The subscription list is serialized by default so you need to ignore it. – Adam Houldsworth Jul 17 '12 at 05:52
  • How did you discover this? Through debugging somehow? – Protector one Mar 20 '17 at 12:04
  • 1
    @Protectorone - In my Google search results on delegates and serialization, the Microsoft link pulled up that I referenced above. Sadly, like a lot of Microsoft stuff, they deleted the link. I cannot imagine it takes too much storage space to keep archives like that around, but they delete stuff anyway. –  Mar 20 '17 at 13:57
  • 1
    @Protectorone - Also, yes I found this exception with my debugger. I noticed I was never able to deserialize my saved states, so I stepped into the process for both the serialize (save) and deserialize (get) methods. Once I discovered I had a **SerializationException**, I started searching the message text *"not marked as serializable."* –  Mar 20 '17 at 14:02
6

This is something you can run into with any JSON serialization, including Web API in MVC 4.

I found this post to be very helpful when I was getting a serialization except on a const int value. Any const value needs to be marked with the same attribute as in Nick Freeman's answer:

[field: NonSerializedAttribute]
const int iCantBeSerialized = 1;
Zach La Lond
  • 461
  • 4
  • 4
2
[field:NonSerializedAttribute()]
public event EventHandler BrazierCuttoffChanged;

Had the same problem, the PropertyChanged EventHandler of my serializable NotifyObject base class was subscribed by some viewmodels which went into the serialization queue therefore. Adding the NonSerializedAddtribute to this EventHandler saved my day. :-)

Monga
  • 21
  • 1
0

mark BrazierMatrix2 as [Serializable]

burning_LEGION
  • 13,246
  • 8
  • 40
  • 52
  • 1
    `BrazierMatrix2` is the form that contains an instance of my data class. All I want to Serialize is the data in `BrazierCuttoff` (which is marked as Serializable). The form should not need to be Serializable for that ...should it??? :confused: –  Jul 16 '12 at 16:17
  • 1
    you use wrong form architecture, you must divide model, controller and view read about pattern design like mvvm, mvc – burning_LEGION Jul 16 '12 at 16:22
  • First, the down vote was NOT from me. I upvote everyone that makes an effort to answer my problems. Second, could you explain that comment about mwm/mvc? (unfamiliar with those acronyms). –  Jul 17 '12 at 13:31
  • this is design pattern for visual part of application, you can read about it here http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller http://en.wikipedia.org/wiki/Model_View_ViewModel it's devide data classe, manager classes and view classes, if you will use this patterns, you will not face with this and similar issues – burning_LEGION Jul 17 '12 at 13:35
  • 1
    you faced with this problem because your architecture have some organization problems, this pattern help you create good solution but it'll be longer and harder – burning_LEGION Jul 17 '12 at 13:43