【问题标题】:ISerializable and inheritance, proper usage, CA2236ISerializable 和继承,正确使用,CA2236
【发布时间】:2014-08-15 22:41:55
【问题描述】:

我有一个关于在继承类中正确实现 ISerializable 的问题。

我有两个类,AbstractBaseClass 和它的实现BaseClass。在执行派生自BaseClassFinalClass 之后,我收到了CA 警告:

CA2236 在 ISerializable 类型上调用基类方法方法 'FinalClass.FinalClass(SerializationInfo, StreamingContext)' 应该是 修改为调用其基类实现。

我不明白的是,如果提取的info.GetString("FileName")info.GetString("Password") 足以创建FinalClass 的实例,我为什么要调用基类?

问题:

1) 谁能给我解释一下?

2) 如果我保持原样并取消警告,我是否有任何设计问题?

谢谢

简化的代码示例是:

public abstract class AbstractBaseClass : ISerializable
{
    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue ...
        //...
    }

    protected AbstractBaseClass() {  }
    protected AbstractBaseClass(SerializationInfo info, StreamingContext context)
    {
        if (info.GetInt32("Version") >= 1)
        {
            //...
        }
    }
}

public class BaseClass : AbstractBaseClass, ISerializable
{
    public BaseClass() : base() { }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue ...
    }

    protected BaseClass(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        if (info.GetInt32("Version") >= 1)
        {
            Connection = new MyConnection();
        }
    }
}

public class FinalClass : BaseClass
{
    public string FileName { get; private set; }
    public string Password { get; private set; }

    public FinalClass(string fileName, string password)
        : base()
    {
        FileName = fileName;
        Password = password;
    }

    protected FinalClass(SerializationInfo info, StreamingContext context)
        : this(info.GetString("FileName"), info.GetString("Password")) { }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue("FileName", FileName);
        info.AddValue("Password", Password);
    }
}

【问题讨论】:

    标签: c# .net inheritance serialization multiple-inheritance


    【解决方案1】:

    因为一般来说,这是一个合理的建议。如果您在基本实现中更改某些内容,调用 base 将确保一切都将继续工作。

    编译器的知识与您不同。 知道没有必要调用base,编译器不需要。编译器确实知道你在做什么并不违法,所以它只是发出警告,告诉你有一些代码可能需要你注意(并且警告总是应该引起你的注意)。

    如果这是真的您想要的,请取消警告,但我个人会调用基本构造函数,就像编译器建议的那样。

    你现在所做的并没有错perse。这是完全有效的 C# 代码,但编译器决定发出警告,因为它“知道”(为简单起见)ISerializable 与序列化构造函数结合通常是如何实现的。

    假设在下一次迭代中BaseClass 添加了它自己的一些属性,即 Foo 属性,并假设我们希望该属性(反)序列化。您可能会在 BaseClass(SerializationInfo, StreamingContext) 构造函数中实现反序列化所需的代码

    public class BaseClass : AbstractBaseClass, ISerializable
    {
        public int Foo { get; set; }
    
        protected BaseClass(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            // ...
            Foo = info.GetInt32("Foo");
            // ...
      }
    }
    

    在您当前的设置中,反序列化 FinalClass 时,不会反序列化 BaseClass 的 Foo 属性,因为您决定调用 this(string fileName, string password) 构造函数,而不是 base(SerializationInfo, StreamingContext) 构造函数。 这就是这个警告的全部情况。该设置不是面向未来的,将来对 AbstractBaseClassBaseClass 的任何添加也应该在构造函数中反序列化,将在您当前的实现中被反序列化。

    所以是的,您可以说当前的实现是一个设计错误,尽管我可能更可能将其称为设计的错误实现。

    【讨论】:

    • FinalClass(SerializationInfo info, StreamingContext context) 调用FinalClass(string fileName, string password),后者调用base()。所以这实际上就是警告的意思,不是吗?
    • 警告告诉你序列化构造函数 FinalClass(SerializationInfo info, StreamingContext context) 没有调用 BaseClass(SerializationInfo info, StreamingContext context)。这是它所期望的模式(因为它是推荐的),但没有找到。
    • 抱歉,目前还不清楚我是否有问题。基类是否也需要 SerializationInfo 和 StreamingContext?或者可以用提取的参数调用另一个构造函数?可以像我一样从另一个构造函数调用另一个 base() 还是需要准确调用 : base(info, context)
    • @VladL:我会用一个例子来更新答案,以(希望)让它更清楚。
    • @VladL:更新了答案,希望它更清楚。
    猜你喜欢
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多