XmlSerializer是否支持属性名称更改(版本容错)

时间:2013-09-27 15:36:22

标签: c# properties version xmlserializer

我有

public bool Included { get; set; }

我想改为:

public bool IsIncluded { get; set; }

我希望具有向后兼容性。我想只在代码中定义IsIncluded,但能够读取旧的xml,其中属性将是“包含”。

XmlSerializer是否支持它以及如何支持?

注意:我尝试没有成功......(不反序列化)

    public bool IsIncluded { get; set; }

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

更新我只想补充一点,我更喜欢我的解决方案,因为我希望我的xml成为IsIncluded,对我来说更合适。像我一样(下面的解决方案),将使我能够更改xml,但保持以前的版本正常工作。从长远来看,我可能会删除代码以支持旧版本。

更新2018-02-01 请在下面的解决方案和建议的解决方案中查看Greg Petersen的评论。他提出了一个很好的解决方案,以便将校正封装在应该完成的地方(类)。 WOW !!!

3 个答案:

答案 0 :(得分:3)

试试:

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

实施例。 v1.c的序列化和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);
    }
}

}

答案 1 :(得分:2)

我找到了。这就是我做到的。

// ******************************************************************
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 :(得分:1)

我使用Eric的解决方案进行了一些修改。我添加了一个接口类来处理向后兼容性部分。

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

使用这个,我们只需要像这样编写一次未知元素事件

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);
}

然后,对于要更改变量名的任何类,让它实现接口。你的课程看起来像这样

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,如果您愿意,可以随意将其纳入您的解决方案。