Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. BinaryFormatter: Serializing an object's base class

BinaryFormatter: Serializing an object's base class

Scheduled Pinned Locked Moved C#
question
29 Posts 7 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M mav northwind

    But that's something I explicitely do not need/want. Of course I could flag Dog as Serializable, too, but then the object is serialized as Dog, not as Animal. The other side of the line (where the object is supposed to be deserialized) doesn't know about Dogs, it only knows about Animals (i.e. there's only the assembly defining Animal available, not the one defining Dog, so trying to deserialize this object will throw a TypeLoadException).

    Regards, mav -- Black holes are the places where God divided by 0...

    realJSOPR Offline
    realJSOPR Offline
    realJSOP
    wrote on last edited by
    #6

    Well, it appears from your code sample as if you really want to serialize the Dog object. I don't understand why you wouldn't want to do that, since you can Deserialize it and cast it back to animal if that's what you really need. Why in the world would the deserialize code not know about the dog object. It looks from here as if your design needs to be re-engineered.

    "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
    -----
    "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001

    D M 2 Replies Last reply
    0
    • M mav northwind

      Hi! I just stumbled over an unexpected behaviour when trying to serialize a derived class using a BinaryFormatter, I guess the best is to show in code:

      //for this sample I have 2 classes:
      // [Serializable] class Animal
      // and
      // class Dog : Animal
      // (not serializable)
      Animal a = new Animal();
      Dog d = new Dog();
      Animal dogAsAnimal = d as Animal;

      BinaryFormatter bf = new BinaryFormatter();
      bf.Serialize(serializationStream, a); // works
      // bf.Serialize(serializationStream, d); // throws an exception because Dog is not Serializable
      bf.Serialize(serializationStream, dogAsAnimal); // <- throws exception as well

      I can't really understand why the last line is trying to serialize the object as Dog instead of Animal - is there any way to keep BinaryFormatter from doing this (short of adding a copy constructor to Animal and actually creating a new object)? Thanks in advance!

      Regards, mav -- Black holes are the places where God divided by 0...

      E Offline
      E Offline
      Ennis Ray Lynch Jr
      wrote on last edited by
      #7

      Objects have to have public, empty constructors to be serialization using the built in methods (Don't quote me) and need to have the Serialization attribute as well as the ISerializable interface for binary serialization. Base classes, in general, can't be serialized if they can't be instantiated.

      Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
      Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
      Most of this sig is for Google, not ego.

      M 1 Reply Last reply
      0
      • realJSOPR realJSOP

        Well, it appears from your code sample as if you really want to serialize the Dog object. I don't understand why you wouldn't want to do that, since you can Deserialize it and cast it back to animal if that's what you really need. Why in the world would the deserialize code not know about the dog object. It looks from here as if your design needs to be re-engineered.

        "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
        -----
        "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001

        D Offline
        D Offline
        Dan Neely
        wrote on last edited by
        #8

        The simplest explanation for what mav's doing is that animal is owned by a different team and are either unwilling or unable to modify the object to contain additional functionality that is needed in mav's part of the project. For every part of the app except serialization having dog inherit from animal makes a more natural design than having dog have an animal member.

        Today's lesson is brought to you by the word "niggardly". Remember kids, don't attribute to racism what can be explained by Scandinavian language roots. -- Robert Royall

        1 Reply Last reply
        0
        • M mav northwind

          Hi! I just stumbled over an unexpected behaviour when trying to serialize a derived class using a BinaryFormatter, I guess the best is to show in code:

          //for this sample I have 2 classes:
          // [Serializable] class Animal
          // and
          // class Dog : Animal
          // (not serializable)
          Animal a = new Animal();
          Dog d = new Dog();
          Animal dogAsAnimal = d as Animal;

          BinaryFormatter bf = new BinaryFormatter();
          bf.Serialize(serializationStream, a); // works
          // bf.Serialize(serializationStream, d); // throws an exception because Dog is not Serializable
          bf.Serialize(serializationStream, dogAsAnimal); // <- throws exception as well

          I can't really understand why the last line is trying to serialize the object as Dog instead of Animal - is there any way to keep BinaryFormatter from doing this (short of adding a copy constructor to Animal and actually creating a new object)? Thanks in advance!

          Regards, mav -- Black holes are the places where God divided by 0...

          G Offline
          G Offline
          Giorgi Dalakishvili
          wrote on last edited by
          #9

          See if this helps: Advanced Binary Serialization: Deserializing an Object Into a Different Type Than the One It was Serialized Into[^]

          Giorgi Dalakishvili #region signature My Articles / My Latest Article[^] / My blog[^] #endregion

          M 1 Reply Last reply
          0
          • E Ennis Ray Lynch Jr

            Objects have to have public, empty constructors to be serialization using the built in methods (Don't quote me) and need to have the Serialization attribute as well as the ISerializable interface for binary serialization. Base classes, in general, can't be serialized if they can't be instantiated.

            Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
            Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
            Most of this sig is for Google, not ego.

            M Offline
            M Offline
            Mark Salsbery
            wrote on last edited by
            #10

            Ennis Ray Lynch, Jr. wrote:

            Objects have to have public, empty constructors to be serialization using the built in methods

            Not true. No constructor is used in deserialization AFAIK.

            Ennis Ray Lynch, Jr. wrote:

            Base classes, in general, can't be serialized if they can't be instantiated.

            Huh? :)

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            E 1 Reply Last reply
            0
            • M mav northwind

              Hi! I just stumbled over an unexpected behaviour when trying to serialize a derived class using a BinaryFormatter, I guess the best is to show in code:

              //for this sample I have 2 classes:
              // [Serializable] class Animal
              // and
              // class Dog : Animal
              // (not serializable)
              Animal a = new Animal();
              Dog d = new Dog();
              Animal dogAsAnimal = d as Animal;

              BinaryFormatter bf = new BinaryFormatter();
              bf.Serialize(serializationStream, a); // works
              // bf.Serialize(serializationStream, d); // throws an exception because Dog is not Serializable
              bf.Serialize(serializationStream, dogAsAnimal); // <- throws exception as well

              I can't really understand why the last line is trying to serialize the object as Dog instead of Animal - is there any way to keep BinaryFormatter from doing this (short of adding a copy constructor to Animal and actually creating a new object)? Thanks in advance!

              Regards, mav -- Black holes are the places where God divided by 0...

              M Offline
              M Offline
              Mark Salsbery
              wrote on last edited by
              #11

              dogAsAnimal is still a Dog object, regardless of the "cast". You can see that in the debugger. "as" doesn't create a new object of a different type. Mark

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              M 1 Reply Last reply
              0
              • M Mark Salsbery

                dogAsAnimal is still a Dog object, regardless of the "cast". You can see that in the debugger. "as" doesn't create a new object of a different type. Mark

                Mark Salsbery Microsoft MVP - Visual C++ :java:

                M Offline
                M Offline
                mav northwind
                wrote on last edited by
                #12

                Well, the debugger shows "Animal {Dog}" as type for dogAsAnimal. a yields "Animal" and d yields "Dog", so I expected dogAsAnimal to be an Animal-type reference to an object that is Dog. It's the same with a direct cast. I cannot access the Dog-only properties of dogAsAnimal, but the BinaryFormatter seems to see through the cast and serialize the deepest inheritance.

                Regards, mav -- Black holes are the places where God divided by 0...

                M 1 Reply Last reply
                0
                • M Mark Salsbery

                  Ennis Ray Lynch, Jr. wrote:

                  Objects have to have public, empty constructors to be serialization using the built in methods

                  Not true. No constructor is used in deserialization AFAIK.

                  Ennis Ray Lynch, Jr. wrote:

                  Base classes, in general, can't be serialized if they can't be instantiated.

                  Huh? :)

                  Mark Salsbery Microsoft MVP - Visual C++ :java:

                  E Offline
                  E Offline
                  Ennis Ray Lynch Jr
                  wrote on last edited by
                  #13

                  For standard XML serializaiton the default constructor needs to be public. For binary serializaiton you need to have the serialization constructor defined.

                  Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                  Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                  Most of this sig is for Google, not ego.

                  M 1 Reply Last reply
                  0
                  • realJSOPR realJSOP

                    Well, it appears from your code sample as if you really want to serialize the Dog object. I don't understand why you wouldn't want to do that, since you can Deserialize it and cast it back to animal if that's what you really need. Why in the world would the deserialize code not know about the dog object. It looks from here as if your design needs to be re-engineered.

                    "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
                    -----
                    "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001

                    M Offline
                    M Offline
                    mav northwind
                    wrote on last edited by
                    #14

                    :) Well, things tend do become simplified when stripping the context. I have a system of several client applications and a server that are communicating via remoting. They all have a notion of Animal. Animal has a method public static void ToFile(Animal a, string file) (and the corresponding FromFile()). For a new client, a Dog class had to be created, but since this class is only used with this client it doesn't make sense to put it into the library defining Animal. Then the client wanted to serialize the Animal-part of one of the Dog objects using the static Animal.ToFile() method, but the binary formatter threw an exception because Dog wasn't marked as serializable. The most intuitive method (for me) to solve this problem would be to find a way to tell the BinaryFormatter that what he gets really really is just an Animal, but I don't know how. Other solutions would be to use aggregation instead of inheritance, but that would require some rewriting of existing code. Or I could add a copy constuctor to Animal and actally create a new object, but that's not really the idea - I don't want to serialize a copy of a Dog, I only want to serialize the Animal-parts of the Dog...

                    Regards, mav -- Black holes are the places where God divided by 0...

                    1 Reply Last reply
                    0
                    • E Ennis Ray Lynch Jr

                      For standard XML serializaiton the default constructor needs to be public. For binary serializaiton you need to have the serialization constructor defined.

                      Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                      Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                      Most of this sig is for Google, not ego.

                      M Offline
                      M Offline
                      Mark Salsbery
                      wrote on last edited by
                      #15

                      Ennis Ray Lynch, Jr. wrote:

                      For standard XML serializaiton the default constructor needs to be public

                      What if there's no default constructor?

                      Ennis Ray Lynch, Jr. wrote:

                      For binary serializaiton you need to have the serialization constructor defined.

                      Not true. That's only for ISerializable-derived classes. ISerializable isn't required for binary serialization.

                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                      E 1 Reply Last reply
                      0
                      • M mav northwind

                        Well, the debugger shows "Animal {Dog}" as type for dogAsAnimal. a yields "Animal" and d yields "Dog", so I expected dogAsAnimal to be an Animal-type reference to an object that is Dog. It's the same with a direct cast. I cannot access the Dog-only properties of dogAsAnimal, but the BinaryFormatter seems to see through the cast and serialize the deepest inheritance.

                        Regards, mav -- Black holes are the places where God divided by 0...

                        M Offline
                        M Offline
                        Mark Salsbery
                        wrote on last edited by
                        #16

                        What if you make the Dog class [Serializable], mark all its members [NonSerialized], and use a SerializationBinder[^] for deserialization? I'm not sure if it will work or not :)

                        Mark Salsbery Microsoft MVP - Visual C++ :java:

                        M 1 Reply Last reply
                        0
                        • M Mark Salsbery

                          Ennis Ray Lynch, Jr. wrote:

                          For standard XML serializaiton the default constructor needs to be public

                          What if there's no default constructor?

                          Ennis Ray Lynch, Jr. wrote:

                          For binary serializaiton you need to have the serialization constructor defined.

                          Not true. That's only for ISerializable-derived classes. ISerializable isn't required for binary serialization.

                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                          E Offline
                          E Offline
                          Ennis Ray Lynch Jr
                          wrote on last edited by
                          #17

                          I will believe you on the second one, however, a default constructor is defined by default unless you create either a non-default constructor or a default constructor with visibility other than public. See: http://support.microsoft.com/kb/330592[^]

                          public class Foo{

                          }

                          and

                          public class Foo{
                          public Foo(){}
                          }

                          Both contain default constructors whereas

                          public class Foo{
                          public Foo(int a){}
                          }

                          and

                          public class Foo{
                          private Foo(){}
                          }

                          Do not.

                          Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                          Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                          Most of this sig is for Google, not ego.

                          M 2 Replies Last reply
                          0
                          • E Ennis Ray Lynch Jr

                            I will believe you on the second one, however, a default constructor is defined by default unless you create either a non-default constructor or a default constructor with visibility other than public. See: http://support.microsoft.com/kb/330592[^]

                            public class Foo{

                            }

                            and

                            public class Foo{
                            public Foo(){}
                            }

                            Both contain default constructors whereas

                            public class Foo{
                            public Foo(int a){}
                            }

                            and

                            public class Foo{
                            private Foo(){}
                            }

                            Do not.

                            Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                            Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                            Most of this sig is for Google, not ego.

                            M Offline
                            M Offline
                            Mark Salsbery
                            wrote on last edited by
                            #18

                            Ennis Ray Lynch, Jr. wrote:

                            a default constructor is defined by default unless you create either a non-default constructor or a default constructor with visibility other than public.

                            Got it, thanks :) Mark

                            Mark Salsbery Microsoft MVP - Visual C++ :java:

                            1 Reply Last reply
                            0
                            • E Ennis Ray Lynch Jr

                              I will believe you on the second one, however, a default constructor is defined by default unless you create either a non-default constructor or a default constructor with visibility other than public. See: http://support.microsoft.com/kb/330592[^]

                              public class Foo{

                              }

                              and

                              public class Foo{
                              public Foo(){}
                              }

                              Both contain default constructors whereas

                              public class Foo{
                              public Foo(int a){}
                              }

                              and

                              public class Foo{
                              private Foo(){}
                              }

                              Do not.

                              Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                              Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                              Most of this sig is for Google, not ego.

                              M Offline
                              M Offline
                              Mark Salsbery
                              wrote on last edited by
                              #19

                              Also, the constructor is only called when using XmlSerializer. No constructor is called with binary/SOAP deserialization. Cheers, Mark

                              Mark Salsbery Microsoft MVP - Visual C++ :java:

                              E 1 Reply Last reply
                              0
                              • M Mark Salsbery

                                Also, the constructor is only called when using XmlSerializer. No constructor is called with binary/SOAP deserialization. Cheers, Mark

                                Mark Salsbery Microsoft MVP - Visual C++ :java:

                                E Offline
                                E Offline
                                Ennis Ray Lynch Jr
                                wrote on last edited by
                                #20

                                I didn't know that, I just assumed a constructor would be called.

                                Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                                Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                                Most of this sig is for Google, not ego.

                                M 1 Reply Last reply
                                0
                                • M Mark Salsbery

                                  What if you make the Dog class [Serializable], mark all its members [NonSerialized], and use a SerializationBinder[^] for deserialization? I'm not sure if it will work or not :)

                                  Mark Salsbery Microsoft MVP - Visual C++ :java:

                                  M Offline
                                  M Offline
                                  mav northwind
                                  wrote on last edited by
                                  #21

                                  Thanks for the suggestion, I'll take a look. Jeez, I didn't expect it to get so complicated... ;P

                                  Regards, mav -- Black holes are the places where God divided by 0...

                                  M 2 Replies Last reply
                                  0
                                  • E Ennis Ray Lynch Jr

                                    I didn't know that, I just assumed a constructor would be called.

                                    Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
                                    Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
                                    Most of this sig is for Google, not ego.

                                    M Offline
                                    M Offline
                                    Mark Salsbery
                                    wrote on last edited by
                                    #22

                                    I was trying to convince myself more than you I think :) I knew I read it somewhere once, and testing confirmed it. Its obscurely "documented" here[^]. I appreciate the discussion, thanks! Mark

                                    Mark Salsbery Microsoft MVP - Visual C++ :java:

                                    1 Reply Last reply
                                    0
                                    • M mav northwind

                                      Thanks for the suggestion, I'll take a look. Jeez, I didn't expect it to get so complicated... ;P

                                      Regards, mav -- Black holes are the places where God divided by 0...

                                      M Offline
                                      M Offline
                                      Mark Salsbery
                                      wrote on last edited by
                                      #23

                                      I was bored, so I tried it. Works great :)

                                      \[Serializable\]
                                      public class Animal
                                      {
                                      	public string str
                                      	{
                                      		get;
                                      		set;
                                      	}
                                      }
                                      
                                      \[Serializable\]
                                      public class Dog : Animal
                                      {
                                      	\[NonSerialized\]  `//<-- Optional!`
                                      	public Int32 A;
                                      
                                      	\[NonSerialized\]  `//<-- Optional!`
                                      	public Int32 B;
                                      
                                      	public Dog()
                                      	{
                                      		A = 5;
                                      		B = 10;
                                      	}
                                      }
                                      
                                      sealed class DogToAnimalDeserializationBinder : SerializationBinder
                                      {
                                      	public override Type BindToType(string assemblyName, string typeName)
                                      	{
                                      		Type typeToDeserialize = null;
                                      
                                      		String assemVer1 = Assembly.GetExecutingAssembly().FullName;
                                      		String typeVer1 = "Dog";
                                      
                                      		if (assemblyName == assemVer1 && typeName == typeVer1)
                                      		{
                                      			typeName = "Animal";
                                      		}
                                      
                                      		// The following line of code returns the type.
                                      		typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
                                      			typeName, assemblyName));
                                      
                                      		return typeToDeserialize;
                                      	}
                                      }
                                      

                                      ...

                                      Dog dog = new Dog();
                                      dog.A = 3;
                                      dog.B = 5;
                                      dog.str = "Animal String";

                                      MemoryStream MemStream = new MemoryStream();

                                      // Serialize a Dog object
                                      BinaryFormatter Serializer = new BinaryFormatter();
                                      Serializer.Serialize(MemStream, dog);

                                      MemStream.Seek(0, SeekOrigin.Begin);

                                      // Deserialize as an Animal object
                                      Serializer.Binder = new DogToAnimalDeserializationBinder();
                                      Animal animal = (Animal)Serializer.Deserialize(MemStream);

                                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                                      1 Reply Last reply
                                      0
                                      • M mav northwind

                                        Thanks for the suggestion, I'll take a look. Jeez, I didn't expect it to get so complicated... ;P

                                        Regards, mav -- Black holes are the places where God divided by 0...

                                        M Offline
                                        M Offline
                                        Mark Salsbery
                                        wrote on last edited by
                                        #24

                                        Wow - my code was overcomplicated. The Binder there is completely unnecessary :rolleyes:

                                        mav.northwind wrote:

                                        The other side of the line (where the object is supposed to be deserialized) doesn't know about Dogs, it only knows about Animals (i.e. there's only the assembly defining Animal available, not the one defining Dog, so trying to deserialize this object will throw a TypeLoadException).

                                        I just noticed that post. The only way that's going to work is to serialize an Animal object in the first place, as you already know. The deserializing end could use a custom binder to deserialize a Dog, but that would still require that end to have the assembly implementing the Dog class. Basically I helped get you back where you started, sorry! :)

                                        Mark Salsbery Microsoft MVP - Visual C++ :java:

                                        M 1 Reply Last reply
                                        0
                                        • M Mark Salsbery

                                          Wow - my code was overcomplicated. The Binder there is completely unnecessary :rolleyes:

                                          mav.northwind wrote:

                                          The other side of the line (where the object is supposed to be deserialized) doesn't know about Dogs, it only knows about Animals (i.e. there's only the assembly defining Animal available, not the one defining Dog, so trying to deserialize this object will throw a TypeLoadException).

                                          I just noticed that post. The only way that's going to work is to serialize an Animal object in the first place, as you already know. The deserializing end could use a custom binder to deserialize a Dog, but that would still require that end to have the assembly implementing the Dog class. Basically I helped get you back where you started, sorry! :)

                                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                                          M Offline
                                          M Offline
                                          mav northwind
                                          wrote on last edited by
                                          #25

                                          Hmmm, I've played around with the SerializationBinder a bit, but didn't get a useable result either. If I always return typeof(Animal) as target type in BindToType, then the deserializing end doesn't require knowledge about Dog, but unfortunately it doesn't work because then even Animal's properties aren't deserialized if I have a Dog object in my serialization stream. :(

                                          Regards, mav -- Black holes are the places where God divided by 0...

                                          M 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups