Does the property name change the XmlSerializer (allows version tolerance)

I have

public bool Included { get; set; } 

What I want to change to:

 public bool IsIncluded { get; set; } 

I want to have backward compatibility. I would like to have only IsIncluded defined in the code, but having the ability to read the old xml, where the property will be "included".

Does XmlSerializer support it and how?

Note. I tried without success ... (doesn't deserialize it)

  public bool IsIncluded { get; set; } [Obsolete] public bool Included { set { IsIncluded = value; } get { return IsIncluded; } } 

Refresh . I just want to add that I prefer my solution, because I wanted my xml to become IsIncluded, which is more appropriate for me. Doing as I did (solution below) would allow me to change the xml, but keep the old version fine. In the long run, I can probably remove the code to support the old version.

Update 2018-02-01 Please take a look at Greg Petersen's comment below the solution and proposed solution. It offers an excellent solution for encapsulating the fix in the place (class) where it should be done. WOW !!!

+6
source share
3 answers

I found him. Here is how I did it.

 // ****************************************************************** public static SimulScenario LoadFromFile(string path) { if (!File.Exists(path)) { return new SimulScenarioError(path); } SimulScenario simulScenario = null; XmlTextReader reader = new XmlTextReader(path); XmlSerializer x = new XmlSerializer(typeof(SimulScenario)); x.UnknownAttribute +=x_UnknownAttribute; x.UnknownElement += x_UnknownElement; x.UnknownNode += x_UnknownNode; x.UnreferencedObject += x_UnreferencedObject; try { simulScenario = (SimulScenario)x.Deserialize(reader); } catch (Exception) { return new SimulScenarioError(path); } finally { reader.Close(); } return simulScenario; } static void x_UnreferencedObject(object sender, UnreferencedObjectEventArgs e) { } static void x_UnknownNode(object sender, XmlNodeEventArgs e) { } static void x_UnknownElement(object sender, XmlElementEventArgs e) { var simulChangeState = e.ObjectBeingDeserialized as SimulChangeState; if (simulChangeState != null) { if (e.Element.Name == "Included") { bool val; if (bool.TryParse(e.Element.InnerText, out val)) { simulChangeState.IsIncluded = val; } else { throw new FileFormatException(Log.Instance.AddEntry(LogType.LogError, "Invalid scenario file format.")); } } } } static void x_UnknownAttribute(object sender, XmlAttributeEventArgs e) { } 
+2
source

Try:

 [XmlElement("Included")] public bool IsIncluded { get; set; } 

Example. Serialization v1.c and deserialization v2.c:

 namespace v1 { public class c { public bool Included { get; set; } } } namespace v2 { public class c { [XmlElement("Included")] public bool IsIncluded { get; set; } } } namespace ConsoleApplication1 { public class Program { static void Main(string[] args) { StringWriter sw = new StringWriter(); new XmlSerializer(typeof(v1.c)).Serialize(sw, new v1.c{ Included=true} ); StringReader sr = new StringReader( sw.ToString() ); v2.c cc = (v2.c)new XmlSerializer(typeof(v2.c)).Deserialize(sr); Debug.Assert(cc.IsIncluded); } } 

}

+3
source

I used Eric's solution with several modifications. I added an interface class to handle the backward compatibility part.

 public interface IBackwardCompatibilitySerializer { void OnUnknownElementFound(string uknownName, string value); } 

Using this, we need to record an unknown element event only once, like this

 private static void x_UnknownElement(object sender, XmlElementEventArgs e) { var deserializedObj = (e.ObjectBeingDeserialized as IBackwardCompatibilitySerializer); if (deserializedObj == null) return; deserializedObj.OnUnknownElementFound(e.Element.Name, e.Element.InnerText); } 

Then, for any class in which you want to change the variable name, execute its interface. Then your class will look like this:

 public class MyClass : IBackwardCompatibilitySerializer { // public bool Included { get; set; } Old variable public bool IsIncluded { get; set; } // New Variable public void OnUnknownElementFound(string unknownElement, string value) { switch(unknownElement) { case "Included": IsIncluded = bool.Parse(value); return; } } } 

Eric, feel free to include this in your decision if you want.

+1
source

Source: https://habr.com/ru/post/954792/


All Articles