可序列化和继承,正确使用,CA2236

本文关键字:CA2236 继承 序列化 | 更新日期: 2023-09-27 18:10:09

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

我有两个类,AbstractBaseClass和它的实现BaseClass。在BaseClass衍生的FinalClass实施后,我得到CA警告:

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

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

问题:

有人能给我解释一下吗?

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

可序列化和继承,正确使用,CA2236

因为,一般来说,这将是一个合理的建议。如果您更改了基实现中的某些内容,调用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的添加都应该在构造函数中反序列化,而在当前实现而不是中将被反序列化。

所以,是的,你可以说当前的实现是一个设计错误,尽管我可能更倾向于称之为设计的错误实现。