Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C# how do I deserialize XML from an older object into the updated object and ignore missing xml elements?

What I have is a custom settings file that I serialize/deserialize using an XmlSerializer. I have no schema defined and no serialization tags in my object definition, just straight object serialization (although I will add them if needed).

My issue is that I need to add data members to the object. If I do that I know that the old settings file will not deserialize.

Is there a way to specify default values for the added members or some simple way to ignore them if they are missing from the XML?

like image 640
Mike Webb Avatar asked Nov 17 '11 21:11

Mike Webb


People also ask

What is '~' in C language?

In mathematics, the tilde often represents approximation, especially when used in duplicate, and is sometimes called the "equivalency sign." In regular expressions, the tilde is used as an operator in pattern matching, and in C programming, it is used as a bitwise operator representing a unary negation (i.e., "bitwise ...

What does the || mean in C?

The logical OR operator ( || ) returns the boolean value true if either or both operands is true and returns false otherwise.

What does -= mean in C++?

-= Subtract AND assignment operator, It subtracts right operand from the left operand and assign the result to left operand. C -= A is equivalent to C = C - A.


1 Answers

From MSDN

Best Practices To ensure proper versioning behavior, follow these rules when modifying a type from version to version:

  • When adding a new serialized field, apply the OptionalFieldAttribute attribute.

  • When removing a NonSerializedAttribute attribute from a field (that was not serializable in a previous version), apply the OptionalFieldAttribute attribute.

  • For all optional fields, set meaningful defaults using the serialization callbacks unless 0 or null as defaults are acceptable.

I have tried to simulate your case where in new version of class have new member named Element2. initialized my new member to "This is new member" here is full proof

Test1 assumes you serialized with old definition of Root class with Just one Element1

Test2 when you serialized and de serialized with new definition of Root Class

To answer your question any way to provide default values you should use "OptionalField"

using System;
using System.Runtime.Serialization;
using System.IO;

public class Test
{

  [Serializable]
  public class Root
  {
    [OptionalField(VersionAdded = 2)] // As recommended by Microsoft
    private string mElement2 = "This is new member";
    public String Element1 { get; set; }    
    public String Element2 { get { return mElement2; } set { mElement2 = value; } }
  }

  public static void Main(string[] s)
  {
    Console.WriteLine("Testing serialized with old definition of Root ");
    Console.WriteLine(" ");
    Test_When_Original_Object_Was_Serialized_With_One_Element();
    Console.WriteLine(" ");
    Console.WriteLine("Testing serialized with new definition of Root ");
    Console.WriteLine(" ");
    Test_When_Original_Object_Was_Serialized_With_Two_Element();
    Console.ReadLine();
  }

  private static void TestReadingObjects(string xml)
  {
    System.Xml.Serialization.XmlSerializer xmlSerializer =
    new System.Xml.Serialization.XmlSerializer(typeof(Root));


    System.IO.Stream stream = new MemoryStream();
    System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    Byte[] bytes = encoding.GetBytes(xml);
    stream.Write(bytes, 0, bytes.Length);
    stream.Position = 0;
    Root r = (Root)xmlSerializer.Deserialize(stream);

    Console.WriteLine(string.Format("Element 1 = {0}", r.Element1));

    Console.WriteLine(string.Format("Element 2 = {0}", r.Element2 == null ? "Null" : r.Element2));
  }
  private static void Test_When_Original_Object_Was_Serialized_With_One_Element()
  {
    TestReadingObjects(@"<Root>   <Element1>1</Element1>   </Root>");
  }

  private static void Test_When_Original_Object_Was_Serialized_With_Two_Element()
  {
    TestReadingObjects(@"<Root>   <Element1>1</Element1> <Element2>2</Element2>   </Root>");
  }
}

// here is the output enter image description here

like image 163
Surjit Samra Avatar answered Sep 20 '22 13:09

Surjit Samra