Preventing Property Serialization

This is a little more complex than the straight forward scripts discussed in other similar questions posted on SO.

I have a class hierarchy like this:

  • DrawingObject

    ( abstract

    class defines abstract

    properties Size

    and Location

    )
    • Label

      (inherits DrawingObject

      ) Provides concrete implementations of Size

      and Location

      . Both properties must be serialized)
    • Line

      (inherits DrawingObject

      . Size

      and Location

      properties should be ignored when serializing / deserializing)

I am using DataContractSerializer

my DrawingObject

s to serialize which creates the following problem:

  • If I don't mark any of the classes with DataContract

    , IgnoreDataMember

    has no effect, and the properties Location

    / are Size

    serialized for Label

    both Line

    . Something I don't want.
  • If I apply DataContract

    to my classes, a runtime exception is thrown indicating that DrawingObject

    it cannot be flagged DataContract

    because its base class ObservableObject

    (yes, MVVM Light) is not flagged DataContract

    .

What can I do to prevent this property from serializing in one derived class and not another?

Edit

The more I scour, the stranger it gets. It looks like the .NET Framework 3.5 has slightly changed the rules and [DataContract]

and the [DataMember]

attributes are no longer required to make it work DataContractSerializer

. If you omit these attributes, DataContractSerializer

all public read / write properties of the class will be serialized (the class must have a public constructor with no parameters). This may be good news for my scenario, but it looks like C # and VB.NET act differently in this regard:

FROM#

The following code is serialized correctly:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;

namespace ConsoleApp1
{
  public abstract class DrawingObject
  {
    public abstract string Location { get; set; }
    public abstract string Size { get; set; }
  }

  public class Label : DrawingObject
  {
    public Label() { }

    private string _Loc;
    private string _Sz;

    public override string Location { get { return _Loc; } set { _Loc = value; } }
    public override string Size { get { return _Sz; } set { _Sz = value; } }
  }

  public class Line : DrawingObject
  {
    public Line() { }

    public override string Location { get { return "Line Location"; } set { Console.WriteLine("Line.Location.set"); } }
    public override string Size { get { return "Line Size"; } set { Console.WriteLine("Line.Size.set"); } }
  }

  class Program
  {
    static void Main(string[] args)
    {
      DrawingObject D1 = new Label() { Location="Label Loc", Size="Label Sz" } ;
      DrawingObject D2 = new Line();

      List<DrawingObject> DObjs = new List<DrawingObject>();
      DObjs.Add(D1);
      DObjs.Add(D2);

      DataContractSerializer S = new DataContractSerializer(typeof(List<DrawingObject>), new[] { typeof(Line), typeof(Label) }, 0x7FFF, false, true, null);

      var sb = new System.Text.StringBuilder();

      using (var writer = new StringWriter(sb))
      {
        using (var xmlWriter = System.Xml.XmlWriter.Create(writer, new System.Xml.XmlWriterSettings() { Indent = true, OmitXmlDeclaration = false }))
          S.WriteObject(xmlWriter, DObjs);

        Console.WriteLine(sb.ToString());

        Console.Read();
      }
    }
  }
}

      

VB.NET

This code doesn't serialize anything:

Imports System.IO
Imports System.Runtime.Serialization
Imports System.Xml.Serialization

Public MustInherit Class DrawingObject
  Public MustOverride Property Location() As String
  Public MustOverride Property Size() As String
End Class

Public Class Label
  Inherits DrawingObject

  Public Sub New()
  End Sub

  Private _Loc As String
  Private _Sz As String

  Public Overrides Property Location() As String
    Get
      Return _Loc
    End Get
    Set
      _Loc = Value
    End Set
  End Property

  Public Overrides Property Size() As String
    Get
      Return _Sz
    End Get
    Set
      _Sz = Value
    End Set
  End Property
End Class

Public Class Line
  Inherits DrawingObject

  Public Sub New()   
  End Sub

  Public Overrides Property Location() As String
    Get
      Return "Line Location"
    End Get
    Set
      Console.WriteLine("Line.Location.set")
    End Set
  End Property

  Public Overrides Property Size() As String
    Get
      Return "Line Size"
    End Get
    Set
      Console.WriteLine("Line.Size.set")
    End Set
  End Property
End Class

Module Module1
  Sub Main()
    Dim D1 As DrawingObject = New Label() With {.Location = "Label Loc", .Size = "Label Sz"}
    Dim D2 As DrawingObject = New Line()

    Dim DObjs As New List(Of DrawingObject)
    DObjs.Add(D1)
    DObjs.Add(D2)

    Dim S As New DataContractSerializer(GetType(List(Of DrawingObject)), {GetType(Line), GetType(Label)}, &H7FFF, False, True, Nothing)

    Dim sb = New System.Text.StringBuilder()

    Using writer = New StringWriter(sb)
      Using xmlWriter = System.Xml.XmlWriter.Create(writer, New System.Xml.XmlWriterSettings() With {.Indent = True, .OmitXmlDeclaration = False})
        S.WriteObject(xmlWriter, DObjs)

        Console.WriteLine(sb.ToString())
        Console.Read()
      End Using
    End Using
  End Sub

End Module

      

I tried to make them syntactically equivalent, but DataContractSerializer

behaves differently.

Edit 2

I tested @CodeCaster suggestion and applied [IgnoreDataMember]

to Location

object property Line

. Doesn't matter (property Location

is still serialized for Line

). Looks like it DataContractSerializer

doesn't respect this attribute in derived classes. I also tried serializing the Line object directly and not the parent List

. Location

even then logs out.

Don't know where to go from here.

Edit 3

After digging around for a day and trying everything out, the difference between the C # and VB.NET code above finally turned out to be an issue when erasing an XML record. The fuzzy thing is that C # code doesn't require me to call Flush()

after serializing the object, whereas VB.NET only produces output if the call Flush()

is made after WriteObject()

.

Another thing I found is that it IgnoreDataMember

does not affect overridden members in derived classes. You have to apply the attribute in the base class for it to work, which is of course not possible in my case. Think I'll have to come up with some kind of problem in this problem.

+3


source to share


1 answer


You must use "KnownType" in order for the DataContractSerializer to serialize properly, so your base class must have a DataContract attribute and inform the types of the child classes as an example



[DataContract]
[KnownType(typeof(Label))]
public abstract class DrawingObject
{
public abstract string Location { get; set; }
public abstract string Size { get; set; }
}

      

0


source







All Articles