ISerializable是否与字段较少的早期版本向后兼容? [英] Is ISerializable backwards-compatible with previous versions of classes with fewer fields?

查看:102
本文介绍了ISerializable是否与字段较少的早期版本向后兼容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,如果我说的问题有点奇怪!基本上,我有一个可序列化的类,当前该类具有单个字段,但是随着我们向系统中添加功能,将来肯定会获得更多的可序列化类.序列化过程将既用于将实例传递到WCF服务,又用于将实例从文件读取/写入文件.当然,如果我用额外的字段不断更新类,那么后者可能是个大问题.

Sorry if I've worded the question a bit odd! Basically, I have a serializable class that has a single field at this current time, but will definitely gain more in the future as we add features to the system. The serialization process will be used for both passing instances to a WCF service, and for reading/writing it from/to file. Of course, the latter may be a big problem if I'm continually updating the class with extra fields.

幸运的是,我认为我已经通过在构造函数中的字段设置器周围添加一个try/catch块解决了这个问题,我还将对添加到该类中的任何其他字段执行此操作.

Luckily, I think I've solved the problem by adding a try/catch block around the field setter in the constructor, which I'll also do for any other fields that are added to the class.

/// <summary>
/// Represents launch options supplied to an executable.
/// </summary>
[Serializable]
public sealed class ExecutableLaunchOptions : ISerializable
{
    /// <summary>
    /// Creates a new set of executable launch options.
    /// </summary>
    public ExecutableLaunchOptions() { }

    /// <summary>
    /// Creates a new set of executable launch options via deserialization.
    /// </summary>
    /// <param name="info">the serialization information.</param>
    /// <param name="context">the streaming context.</param>
    public ExecutableLaunchOptions(
        SerializationInfo info, StreamingContext context) : this()
    {
        // Get the value of the window style from the serialization information.
        try { this.windowStyle = (ProcessWindowStyle)info.GetValue(nameof(this.windowStyle), typeof(ProcessWindowStyle)); } catch { }
    }

    // Instance variables.
    private ProcessWindowStyle windowStyle = ProcessWindowStyle.Normal;

    /// <summary>
    /// Gets or sets the window style to apply to the executable when it launches.
    /// </summary>
    public ProcessWindowStyle WindowStyle
    {
        get { return this.windowStyle; }

        set { this.windowStyle = value; }
    }

    /// <summary>
    /// Gets the information required for the serialization of this set of launch options.
    /// </summary>
    /// <param name="info">the serialization information.</param>
    /// <param name="context">the streaming context.</param>
    public void GetObjectData(
        SerializationInfo info, StreamingContext context)
    {
        // Add the value of the window style to the serialization information.
        info.AddValue(nameof(this.windowStyle), this.windowStyle, typeof(ProcessWindowStyle));
    }
}

我猜想这将使我在反序列化时保留与包含该类先前版本实例的文件的向后兼容性,因为代码将简单地抛出并随后捕获其中不存在的每个字段的异常序列化信息,将其值保留为默认值.我在这里正确吗,还是我错过了什么?

I'm guessing this will allow me to retain backwards-compatibility with files containing instances of previous versions of the class when I deserialize them, as the code will simply throw and subsequently catch exceptions for each field that doesn't exist in the serialization information, leaving their values at their default. Am I correct here, or am I missing something?

推荐答案

您可以使用 SerializationInfo 来查找可能仅在条件下存在的项目:

You can use SerializationInfo.GetEnumerator() to loop through the name-value pairs contained in the SerializationInfo to look for items that might only be conditionally present:

    public ExecutableLaunchOptions(
        SerializationInfo info, StreamingContext context) : this()
    {
        // Get the value of the window style from the serialization information.
        var enumerator = info.GetEnumerator();
        while (enumerator.MoveNext())
        {
            var current = enumerator.Current;
            if (current.Name == "windowStyle" && current.ObjectType == typeof(ProcessWindowStyle))
            {
                this.windowStyle = (ProcessWindowStyle)current.Value;
            }
        }
    }

请注意,此类太老了(即从c#1.0开始),尽管具有GetEnumerator()方法,但实际上并没有实现IEnumerable.

Note that this class is so old (i.e. from c# 1.0) that, despite having a GetEnumerator() method, it doesn't actually implement IEnumerable.

如果您需要经常执行此操作,则可以引入如下扩展方法:

If you need to do this often, you can introduce an extension method like so:

public static class SerializationInfoExtensions
{
    public static IEnumerable<SerializationEntry> AsEnumerable(this SerializationInfo info)
    {
        if (info == null)
            throw new NullReferenceException();
        var enumerator = info.GetEnumerator();
        while (enumerator.MoveNext())
        {
            yield return enumerator.Current;
        }
    }
}

然后执行:

    public ExecutableLaunchOptions(
        SerializationInfo info, StreamingContext context) : this()
    {
        foreach (var current in info.AsEnumerable())
        {
            if (current.Name == "windowStyle" && current.ObjectType == typeof(ProcessWindowStyle))
            {
                this.windowStyle = (ProcessWindowStyle)current.Value;
            }
        }
    }

哪个更现代,更易读.

这篇关于ISerializable是否与字段较少的早期版本向后兼容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆