• 0

[C#] Serialization of abstract class


Question

10 answers to this question

Recommended Posts

  • 0

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 by Antaris
Removed incorrect logic.
  • 0
  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 :).

  • 0
  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?

  • 0
  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: .

  • 0

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:

post-92970-12670880091169_thumb.png

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&lt;Person&gt;();
    }

    protected PeopleSet(SerializationInfo info, StreamingContext context)
    {
        People = (List&lt;Person&gt;)info.GetValue("list", typeof(List&lt;Person&gt;));
    }
    #endregion

    #region Properties
    public List&lt;Person&gt; 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:

post-92970-12670882362371_thumb.png

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.

  • 0
  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:

post-92970-12670880091169_thumb.png

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&lt;Person&gt;();
    }

    protected PeopleSet(SerializationInfo info, StreamingContext context)
    {
        People = (List&lt;Person&gt;)info.GetValue("list", typeof(List&lt;Person&gt;));
    }
    #endregion

    #region Properties
    public List&lt;Person&gt; 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:

post-92970-12670882362371_thumb.png

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 .

  • 0

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.

  • 0
  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 .

  • 0

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&lt;A&gt; MakeAs() { return new List&lt;B&gt;(); }

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • LG gram Book 15U50T: Is this lightweight laptop the right upgrade for you? by Paul Hill If you’re in the UK looking for a new mid-range laptop that won’t feel underpowered, check out the LG gram Book 15U50T now because it’s at its all-time lowest price on Amazon UK thanks to a 14% discount from its £699.99 RRP. You can get it now for just £599.99 (Buying link at the end). At this price, the laptop definitely makes this mid-range option much more appealing, it’s also pretty new having only come out in January 2025, so you’re definitely getting more value for your money. The delivery is free and will take a few days to arrive unless you take advantage of a Prime member trial and get it next-day in time for Father’s Day. LG gram Book 15U50T: Key features and who it's for The LG gram Book 15U50T features a 15.6-inch Full-HD (1920x1080) anti-glare IPS display, making it ideal for use in well-lit areas as you won’t see yourself staring back. It’s powered by an Intel Core i5 processor (1334U), 16GB of RAM, and has a very fast 512GB NVMe Gen4 SSD. In my opinion, the storage might be a bit tight for some users; however, the device comes with two M.2 slots if you want to upgrade the storage. The LG gram Book 15U50T is ideal for students or professionals who need a device to carry with them out and about. It has an ultra-lightweight design and weighs just 1.65kg - that’s not too far off a similarly sized MacBook Air, but for a fraction of the cost. In terms of ports, there is an HDMI port, two USB-A ports, and two USB-C ports. There's also a 3.5mm headphone jack if you need to plug in headphones. Other noteworthy details about this laptop include that it's running Windows 11 Home with Copilot integration, it has a HD webcam with a privacy shutter, it uses Dolby Atmos audio for immersive sound, and it has a unique feature called gram Link for multi-device (including Android and iOS) connectivity. Should you buy it? If you are a student or a professional that won’t be doing heavy gaming, or using other super intensive applications, this laptop is a solid pick. It’s lightweight - so easy to carry around, it has an anti-reflective screen - so good in well-lit environments; and it features upgradeable storage slots if 512GB is not enough space. On the downside, this laptop has a mid-range processor that could limit your ability to use high-end professional tools. Another thing I’m not really a fan of here is how opaque LG has been with the battery life. As a portable laptop, you’re obviously going to want to take it on the go where you don’t have a charger handy, but all LG says about the battery is that it has a capacity of 51Wh. According to some online sources, variants of this laptop manage about 7 to 10 hours, so if you need a super long battery life, you might be better off with something like a MacBook Air. So should you buy it? If you’re not going to be doing anything super intensive, but can’t stand underpowered and slow budget laptops then this could be the ideal laptop for you. The £100 discount makes it even more appealing! LG gram Book 15U50T: £599.99 (Amazon UK) / RRP £699.99 This Amazon deal is U.K. specific, and not available in other regions unless specified. If you don't like it or want to look at more options, check out the Amazon UK deals page here. Get Prime, Prime Video, Music Unlimited, Audible or Kindle Unlimited, free for the first 30 days As an Amazon Associate we earn from qualifying purchases.
    • Totally different vehicles. Uber has partnered with Waymo for level 5 autonomous vehicles. Waymo has completed 10 million trips and to date, there have been 696 accidents in 4 years and of those 16 of them appear to have been due to an error by the car. In total airbags have only been deployed 38 times. The technology should always be under review and continued to be improved on, but this is a totally different animal to Tesla FSD PS. no I don't work for them etc. I am an analyst for a market intelligence firm and we have a lot of interest from clients looking at the connected car space for advertising etc. so I have studied them
    • But it's not full self driving it's level 2 autonomy. Audi, BMW and Mercedes all have level 3 and make far less noise about it
    • Edge for Business gets secure password deployment for organizations by Paul Hill Microsoft Edge for Business now offers organizations secure password deployments as a generally available feature, the Redmond giant said. Instead of users sharing passwords on sticky notes or via email to access certain websites or tools, admins can deploy encrypted shared passwords to specific users within their organization. When a user receives a password, it is stored in their Edge password manager and can be used to log into websites seamlessly using autofill. Microsoft has made this enterprise-grade solution available to customers at no additional cost. How it works and the user experience Administrators have to manage the feature via the Microsoft Edge management service within the Microsoft 365 admin center. From there, they can add, update, and revoke credentials for specific user groups through configuration policies. Once an admin has set it up and shared passwords with users, the users will see the passwords in their Edge password manager and can be used with autofill on corresponding websites. The passwords are tied to work profiles in Edge on managed Windows devices to limit their misuse. Further boosting security, the shared passwords cannot actually be viewed, edited, or deleted (unless the website allows), or exported from the password manager. This is a good addition for security because if an unauthorized user gains physical access to the computer, they cannot learn what the password is. Administrators reading this do need to be aware of an important caveat related to developer tools. A motivated user who wants to reveal the passwords can do so by digging into the developer tools, for this reason, you should consider restricting access to the developer tools by configuring the DeveloperToolsAvailability policy. The underlying security and encryption Microsoft’s new secure passwords feature has been built using the Information Protection SDK. The passwords are encrypted and the encryption is tied to Entra identities which lets organizations enforce them without manual key management. The decryption of the passwords takes place at runtime using the same SDK, validating the user’s identity. Availability and getting started Secure password deployment is available through the Edge management service in the Microsoft 365 admin center. Once in the admin center, you should choose an existing configuration policy or create a new one. Inside the policy, go to the Customization Settings tab and then to the Secure password deployment page. To use this feature you must have a Microsoft 365 Business Premium, E3, or E5 subscription. The feature also requires the Edge admin or Global admin role. Source: Microsoft
    • Is it though?  I built a new rig a few months ago and it was literally impossible to get one without RGB, but within 10 minutes of setting it up, I turned all that crap off.  It was REALLY distracting, and who needs additional heat INSIDE a PC? It's popular on YouTube for sure, it's neat looking and whatnot, but it's about as practical as a coffee cup with a hole in it. As for the price, a non-enthusiast would just see something priced way above what they can get from a retailer brand new...
  • Recent Achievements

    • Week One Done
      somar86 earned a badge
      Week One Done
    • One Month Later
      somar86 earned a badge
      One Month Later
    • Apprentice
      Adrian Williams went up a rank
      Apprentice
    • Reacting Well
      BashOrgRu earned a badge
      Reacting Well
    • Collaborator
      CHUNWEI earned a badge
      Collaborator
  • Popular Contributors

    1. 1
      +primortal
      504
    2. 2
      ATLien_0
      260
    3. 3
      +Edouard
      187
    4. 4
      +FloatingFatMan
      175
    5. 5
      snowy owl
      132
  • Tell a friend

    Love Neowin? Tell a friend!