Cold Blood Posted February 24, 2010 Share Posted February 24, 2010 Well, I know that i can't serialize interfaces, but can I serialize a derived class from an abstract class as the abstract class type and not the derived type?I am serializing in binary format and my abstract class inherits ISerializable. Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/ Share on other sites More sharing options...
0 Antaris Veteran Posted February 24, 2010 Veteran Share Posted February 24, 2010 (edited) What benefit do you see of serialising the just the properties of the abstract type? You can infact do this I guess, if you define deserialisation constructors. For instance, we have a type: public abstract class Person : ISerializable { #region Constructor public Person() { } protected Person(SerializationInfo info, StreamingContext context) { Forename = info.GetString("forename"); Surname = info.GetString("surname"); } #endregion #region Properties public string Forename { get; set; } public string Surname { get; set; } #endregion #region Methods public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.Add("forenamerename); info.Add("surnamername); } #endregion } This type implements the ISerializable interface, and also provides a deserialisation constructor with signature (SerializationInfo, StreamingContext). Obviously we can't instantiate this type, but we could define a type which implements this, and is deserialized: public class Employee : Person { #region Constructors public Employee() { } protected Employee(SerializationInfo info, StreamingContext context) : base(info, context) { // Additional deserialisation here. } #endregion #region Properties public string Department { get; set; } #endregion } BinaryFormatter formatter = new BinaryFormatter(); Employee emp = (Employee)formatter.Deserialize(<stream>); The Employee type does't implement any specific serialisation of its own properties, so when serialising, it will only serialise the properties of the base type. We could of course serialise our local properties too: public class Employee : Person { #region Constructors public Employee() { } protected Employee(SerializationInfo info, StreamingContext context) : base(info, context) { Department = info.GetString("department"); } #endregion #region Properties public string Department { get; set; } #endregion #region Methods public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.Add("department } #endregion } The net result is, although the data of the abstract type is serialised, its actually the derived type that is serialised in the stream. Edited February 25, 2010 by Antaris Removed incorrect logic. Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592277376 Share on other sites More sharing options...
0 Cold Blood Posted February 24, 2010 Author Share Posted February 24, 2010 On 24/02/2010 at 17:45, Antaris said: What benefit do you see of serialising the just the properties of the abstract type? You can infact do this I guess, if you define deserialisation constructors. For instance, we have a type: public abstract class Person : ISerializable { #region Constructor public Person() { } protected Person(SerializationInfo info, StreamingContext context) { Forename = info.GetString("forename"); Surname = info.GetString("surname"); } #endregion #region Properties public string Forename { get; set; } public string Surname { get; set; } #endregion #region Methods public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("forename", Forename); info.AddValue("surname", Surname); } #endregion } This type implements the ISerializable interface, and also provides a deserialisation constructor with signature (SerializationInfo, StreamingContext). Obviously we can't instantiate this type, but we could define a type which implements this, and is deserialized: public class Employee : Person { #region Constructors public Employee() { } protected Employee(SerializationInfo info, StreamingContext context) : base(info, context) { // Additional deserialisation here. } #endregion #region Properties public string Department { get; set; } #endregion } BinaryFormatter formatter = new BinaryFormatter(); Employee emp = (Employee)formatter.Deserialize(<stream>); The Employee type does't implement any specific serialisation of its own properties, so when serialising, it will only serialise the properties of the base type. We could of course serialise our local properties too: public class Employee : Person { #region Constructors public Employee() { } protected Employee(SerializationInfo info, StreamingContext context) : base(info, context) { Department = info.GetString("department"); } #endregion #region Properties public string Department { get; set; } #endregion #region Methods public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("department"); } #endregion } The net result is, although the data of the abstract type is serialised, its actually the derived type that is serialised in the stream. If I am following what I think you want to do, you want something like this: Person person = (Person)formatter.Deserialize(<stream>); I am not sure if that would work, simply because the Person type cannot be instantiated, because it is abstract. And doing this: Person person = (Person)(Employee)formatter.Deserialize(<stream>); ... doesn't provide the clean separation of concerns you want. Well, the reason for using an abstract class is because I have a composite model in my program so I have a collection of some types that implement an interface so I can't serialize the collection. I want the collection to have interface because I want it to be as generic as possible. In the end I settled for an abstract class that implements a custom interface and ISerializable. When I serialize the class I serialize it as the abtrast type and when deserialize I cast it to my custom interface. About what you said.To further clarify things, you can deserialize derived classes from an abtrast type,even if you serialized it as the abstrast class, because when you serialize to a binary format it also adds metadata to the file so it knows the real type of the serialized class and so it can call the appropiate constructor. I've tested and confirmed this after quite some research. You can even open the file in notepad and you can see some readable things :). Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592277648 Share on other sites More sharing options...
0 Antaris Veteran Posted February 24, 2010 Veteran Share Posted February 24, 2010 Quote About what you said.To further clarify things, you can deserialize derived classes from an abtrast type,even if you serialized it as the abstrast class, because when you serialize to a binary format it also adds metadata to the file so it knows the real type of the serialized class and so it can call the appropiate constructor. I've tested and confirmed this after quite some research. You can even open the file in notepad and you can see some readable things But if you have an instance of an abstract type, its actually an instance of a derived type, so what gets serialised is the derived type, no? What I mean is, when you call any of the methods (Serialize, Deserialize), at no point do you express the type, e.g. typeof(Person) [as per my example]. Internaly if the BinaryFormatter makes a call to GetType(), the derived type will be returned, not the abstract type? Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592277882 Share on other sites More sharing options...
0 Antaris Veteran Posted February 24, 2010 Veteran Share Posted February 24, 2010 Oh, you can of course do this: Person person = (Person)formatter.Deserialize(<stream>); The derived type is created by the formatter and then cast back to the abstract type. Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592278274 Share on other sites More sharing options...
0 Cold Blood Posted February 24, 2010 Author Share Posted February 24, 2010 On 24/02/2010 at 19:46, Antaris said: But if you have an instance of an abstract type, its actually an instance of a derived type, so what gets serialised is the derived type, no? What I mean is, when you call any of the methods (Serialize, Deserialize), at no point do you express the type, e.g. typeof(Person) [as per my example]. Internaly if the BinaryFormatter makes a call to GetType(), the derived type will be returned, not the abstract type? Well,when I serialize the abstract classes, i use typeof(List<abstract class name>) . Also I don't serialize the original List<myinterface> but create a separate list and cast the members to the abstract type. This is probably a very bad practive and completely useless in real programming but it's nice for an exercise. So i serialize the entire collection, like this serialization_info_instace.add("tag",list<abstract_type_name>_instancealize you don't use typeof, but only when you deserialize. Collections with serializable members are also serializable. I even created a special class to check the serialization of abstract classes. In my class I have an derived class instance member explicitly declared as derived, so it includes the entire type ierarchy when I serialize,. When I deserialize i use typeof(abstract class) with the GetValue method and not GetString as in the example.I even tried declaring the derived class instance as an abstract class member and it still worked so it's the same as the previous case. So I guess it doesn't matter how you serialize/deserialize your classes because it will always include the full type ierarchy when serializing. As long as you deserialize to something that is in the type ierarchy it will work. But only with classes. I tried to serialize something as an interface and I got an exception although I can deserialize something as an interface using typeof(myinterfacename) as a paramenter to the GetValue method. Hope I was clear enough and didn't make any mistakes :happy: . Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592278336 Share on other sites More sharing options...
0 Antaris Veteran Posted February 25, 2010 Veteran Share Posted February 25, 2010 Well, I think I'm getting confused over exactly what you want to achieve. Using my example from before, if I serialise a derived type, and then deserialise it, we can see that it is actually the derived type that is deserialised before we cast it back to the abstract type: In the same sense, I have an example type which implements an abstract collection: List<Person> (read: not List<Employee>): [Serializable] public class PeopleSet : ISerializable { #region Constructors public PeopleSet() { People = new List<Person>(); } protected PeopleSet(SerializationInfo info, StreamingContext context) { People = (List<Person>)info.GetValue("list", typeof(List<Person>)); } #endregion #region Properties public List<Person> People { get; private set; } #endregion #region Methods public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("list", People); } #endregion } Now, if we are explicitly using typeof(List<Person>) when adding the list to the SerializationInfo, but when we deserialise the PeopleSet type, the list is deserialised and cast back to List<Person>, but the item contained is still the derived type I added before: The thing I think you will fall into problems with, is if you are trying to deserialise purely as the abstract type, where the derived type is not available. I.e., you have a library with your abstract type, which is used throughout, but the derived type is only available during serialisation. This wouldn't work, as when you attempt to deserialise when the derived type is not available, an Exception will be thrown. Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592280154 Share on other sites More sharing options...
0 Cold Blood Posted February 25, 2010 Author Share Posted February 25, 2010 On 25/02/2010 at 09:00, Antaris said: Well, I think I'm getting confused over exactly what you want to achieve. Using my example from before, if I serialise a derived type, and then deserialise it, we can see that it is actually the derived type that is deserialised before we cast it back to the abstract type: In the same sense, I have an example type which implements an abstract collection: List<Person> (read: not List<Employee>): [Serializable] public class PeopleSet : ISerializable { #region Constructors public PeopleSet() { People = new List<Person>(); } protected PeopleSet(SerializationInfo info, StreamingContext context) { People = (List<Person>)info.GetValue("list", typeof(List<Person>)); } #endregion #region Properties public List<Person> People { get; private set; } #endregion #region Methods public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("list", People); } #endregion } Now, if we are explicitly using typeof(List<Person>) when adding the list to the SerializationInfo, but when we deserialise the PeopleSet type, the list is deserialised and cast back to List<Person>, but the item contained is still the derived type I added before: The thing I think you will fall into problems with, is if you are trying to deserialise purely as the abstract type, where the derived type is not available. I.e., you have a library with your abstract type, which is used throughout, but the derived type is only available during serialisation. This wouldn't work, as when you attempt to deserialise when the derived type is not available, an Exception will be thrown. Sorry for making such a mess out this. I managed to serialize the classes just as I wanted though as you pointed I can't always do like this because I don't always have acces to the type. I believe this is important to remember because changing this requires a lot of code rewriting. So when making a serious application you need to know about this from the start. I still needed some clarifications but now I pretty much understand the concept . Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592282092 Share on other sites More sharing options...
0 Antaris Veteran Posted February 26, 2010 Veteran Share Posted February 26, 2010 Don't worry about it, it's all the fun of development. If you want to truly break the dependancy on the derived type, you could implement some sort of proxy object which implements your abstract class or interface. You won't be able to use binary serialisation, but I can't see any reason why you could use xml serialisation and custom reconstruction. Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592283714 Share on other sites More sharing options...
0 Cold Blood Posted March 1, 2010 Author Share Posted March 1, 2010 On 26/02/2010 at 08:38, Antaris said: Don't worry about it, it's all the fun of development. If you want to truly break the dependancy on the derived type, you could implement some sort of proxy object which implements your abstract class or interface. You won't be able to use binary serialisation, but I can't see any reason why you could use xml serialisation and custom reconstruction. I did break dependency in a way. I have a core assembly in which I have defined my interfaces and abstract types. I reference that assembly in my project and build on top of it. And in my program I inspect a folder called plugins for additional assemblies. It inspecs each assembly for derived types from my interfaces and abstract classes and loads them into a list. I use that list to create objects of those types. My convention is that every derived class from my abstract classes and interfaces should have a constructor that takes certain parameters so that I can instantiate those classes for sure so I can add new objects of those custom types to my application from it's GUI. I also use that list of custom types to deserialize my objects from binary files. I need to make a custom binder and set it to the formatter. The custom binder searches the list of types for the desired type. And not just that, I was playing with nested classes. Each nested class if derived from another abstract attribute class, represents an attribute that I can set to object of those types or types derived from it. I don't implement interfaces directly, but rather create an abstract class that maps the methods and properties. And I use that class to derive from it. So it's very easy to add new attributes to my classes. (not attributes that you put in [] to mark the code with special properties, but rather custom ones that are completely unrelated to those). So my main abstract class has a property that gets or sets a list of attributes which also exists in the interface that it implements. But also it has come concrete classes that denote general attributes that apply to all the classes derived from it. I really like how this makes things really logical and it's very easy to extend and customize my program with additional assemblies. It's really amazing what you can do with .net. I researched and came with another idea, to add support for custom sources that contain actual code. It will probably have another folder called sources. I will compile them at runtime and inspect them for my desired types. This will make adding custom content to my application even easier because you won't even need to compile the code because my application will do it for you. This is imo one of the best parts of programming :D . Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592297392 Share on other sites More sharing options...
0 ArmedMonkey Posted March 4, 2010 Share Posted March 4, 2010 There are also SerializationSurrogates which can be used to serialize instances of classes (sealed, perhaps, or otherwise unmodifiable) that are not normally serializable. Of course, you only have access to the public members in this situation, unless of course you use reflection. I had to do this because in .net 1.1 Microsoft left 3 Exception classes without the ISerializable interface. Key things to take away here: 1) If B is instance of A -> List<B> is instance of List<A> 2) You cannot have an instance of an abstract type 3) You don't need to downcast. public abstract class A {} public class B : A{} .... public A MakeA() { return new B(); } public List<A> MakeAs() { return new List<B>(); } Link to comment https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/#findComment-592309158 Share on other sites More sharing options...
Question
Cold Blood
Well, I know that i can't serialize interfaces, but can I serialize a derived class from an abstract class as the abstract class type and not the derived type?I am serializing in binary format and my abstract class inherits ISerializable.
Link to comment
https://www.neowin.net/forum/topic/878100-c-serialization-of-abstract-class/Share on other sites
10 answers to this question
Recommended Posts