1

I have a string which I need to deserialize it into a collection of objects, all inherite the same base class.

My problem is that after I deserialization into the base class collection, the compiler doesn't recognize each item as the relevant concrete object.

Here is my code:

public BaseClass // can be abstract
{
    int propA {get; set;}   
}


public ExtendedBaseClassA : BaseClass
{
    int propB {get; set;}   
    int propC {get; set;}   
}


public ExtendedBaseClassB : BaseClass
{
    int propD {get; set;}   
    int propE {get; set;}   
}

void Deserialize(string serializeMessage)
{
    IEnumerable<BaseClass> objects = JsonSerializer.Deserialize<IEnumerable<BaseClass>> 
    (serializeMessage);
    foreach(BaseClass item in objects)  
    {
        if (item is ExtendedBaseClassA) //never
        {
        }
        if (item is ExtendedBaseClassB) //never
        {
        }
    }
 }

Is there any other way doing it ?

Guy E
  • 1,775
  • 2
  • 27
  • 55
  • If the `JsonSerializer` you are using is actually [tag:system.text.json], then this looks to be a duplicate of [Is polymorphic deserialization possible in System.Text.Json?](https://stackoverflow.com/q/58074304/3744182). Agree? If not System.Text.Json then please specify the library you are using. – dbc Nov 03 '22 at 20:37

1 Answers1

1

When you deserialize the string as BaseClass it assigns propA. If the JSON you're deserializing also contains propB, propC, etc., where do those values go? They go nowhere. They're discarded. Deserialization doesn't care about properties that don't belong to the type being deserialized.

Whatever type you tell it to deserialize as - JsonSerializer.Deserialize<Something> - it's going to create an instance of that type. It's not going to try to figure out if there's an inherited type that it can create based on other properties that don't belong to the type you specified.

So once you deserialize into BaseClass, all you have is an instance of BaseClass. You can cast a derived type as a base type, but you can't cast a base type as one of its inherited types.

I don't see an obvious solution, especially without knowing the specifics of the actual types you're working with. You could parse each as JObject, see which properties it contains, and decide which type to deserialize it as. For example, if it contains propE, deserialize as ExtendedBaseClassB. If it doesn't contain propE but does contain propC, deserialize as ExtendedBaseClassA, and so on.

A better solution might be to create one type that contains all the possible properties. If they might not be populated, make them nullable. Now you can deserialize everything into one type and see which properties are populated. You might find that you have no need for inheritance at all. That would be ideal. (This looks like the type of the problem that maybe shouldn't be solved - it's better to reconsider so that you don't have the problem in the first place.)

Or if you need the inheritance then after deserializing that one class, you could then write a function inspects it, determines which type to create (depending on which properties) are populated, and creates a new instance of the "correct" type. That function could return it cast as the base class, but the actual type could be some inherited class.


A comment on BaseClass says

can be abstract

If it's abstract then this will throw an exception: JsonSerializer.Deserialize<IEnumerable<BaseClass>>

This would be asking the deserializer to create an instance of an abstract class. The point of an abstract class is that you can't create an instance of it. You can only create an instance of a non-abstract inherited class.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62