【问题标题】:Prevent Serialization of Base Class防止基类的序列化
【发布时间】:2012-01-24 16:53:55
【问题描述】:

我觉得我应该知道这一点,但出于某种原因....

序列化派生自(可能是抽象的)基类的类的首选方法是什么,而不必一直序列化到树上?例如,您可能无法控制派生的类,但想使用序列化来克隆您的对象(仅限于您的对象,而不是基类)。

例如:

// This is a base class that is outside my control, which derives from
// some other base class that I know "nothing" about
public abstract class SomeBaseClass : SomeOtherBaseClass
{
    private string mBaseProperty = "Base Property";
    public string BaseProperty
    {
        get { return mBaseProperty; }
        set { mBaseProperty = value; }
    }
}

// This is the class that I do control
[Serializable()]
private class MyDerivedClass : SomeBassClass
{
    // Assume normal constructors, etc.

    // Here are some properties
    private string mDerivedPropertyOne = String.Empty;
    private string DerivedPropertyOne
    {
        get { return mDerivedPropertyOne ; }
        set { mDerivedPropertyOne = value; }
    }

    private string mDerivedPropertyTwo = String.Empty;
    private string DerivedPropertyTwo
    {
        get { return mDerivedPropertyTwo ; }
        set { mDerivedPropertyTwo = value; }
    }

    // And now a quick-n-dirty Equals override
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            MyDerivedClass compareTo = obj as MyDerivedClass;
            if (compareTo == null)
                return false;

            return ((String.Compare(this.DerivedPropertyOne, 
                                    compareTo.DerivedPropertyOne, true) == 0) &&
                    (String.Compare(this.DerivedPropertyTwo, 
                                    compareTo.DerivedPropertyTwo, true) == 0) &&
        }
}

// And while we're at it, here's a simple clone found elsewhere on StackOverflow
public static class ObjectClone
{
    public static T Clone<T>(this T source)
    {
        if (!typeof(T).IsSerializable)
        {             
            throw new ArgumentException("The type must be serializable.", "source");         
        }          

        // Don't serialize a null object, simply return the default for that object         
        if (Object.ReferenceEquals(source, null))
        {             
            return default(T);         
        }          

        IFormatter formatter = new BinaryFormatter();         
        Stream stream = new MemoryStream();         
        using (stream)         
        {             
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);             
            return (T)formatter.Deserialize(stream);         
        }         
    }
}

正如所写,这将引发 SerializationException,因为 SomeBaseClass 未标记为可序列化。

【问题讨论】:

  • 如果您使用的是 BinaryFormatter,那么它根据定义对类型很挑剔,并且想要序列化所有内容。您可以在这里使用替代序列化程序吗?
  • 这本质上是一个危险的操作,除非你知道基类的内部结构。如果基类作者的意图不是序列化该类的对象,则无法保证反序列化后对象将处于有效甚至有用的状态。只讨论克隆派生对象的意义不大。继承意味着派生类的任何实例也必须是基类的有效实例。
  • MarcGravell,@JonasH 等。人。这更像是一个“学术”问题——这是我玩弄一些我继承的代码的结果。我当然同意你的 cmets。

标签: c# serialization


【解决方案1】:

简答:使用组合而不是继承。将要序列化的成员提取到另一个类中并使其可序列化。这将为您提供对生命周期和序列化程度的控制。

一般来说,序列化对象成为哑数据持有者并通过包装它们添加任何附加逻辑是一种很好的模式。 protobuf、thrift、avro 等现代序列化框架加强了这一点,无论如何,它们都会为您生成这些序列化对象背后的代码,并希望您不要通过继承破坏这些类的内部。

【讨论】:

  • 这听起来很愚蠢。我有一个从 A 继承的 B 类(通过我使用的框架的设计)。我需要序列化 ​​B,而不是 A。没有办法从 BSerializedFields 继承 B,只留下逻辑,因为这需要多重继承。我可以将 BSerializedFields 聚合为 B 中的字段 Data,但这需要以 obj.Data.FieldName 的形式访问其字段。我可以在 B 上创建一些修改器来访问Data,但这需要很多代码。我可以生成该代码,是的。但是,嘿,实现我自己的序列化器已经更容易了。
  • 所以这只是C#中一些写得很糟糕的序列化例程,不是一个好的模式。
【解决方案2】:

您可以在 ...BaseClass 中使用 XmlRoot("MyDerivedClass") 属性

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    相关资源
    最近更新 更多