0

My base class has a method to serialize itself that I want derived classes to use.

public abstract class Base
{
    public int Property1 { get; set; }

    public virtual string Serialize()
    {
       ...
       return System.Text.Json.JsonSerializer.Serialize(this, jsonSerializerOptions);
    }
}

The problem is that "this" in the base classes refers to the base class. When calling Serialize() from derived classes, only the properties of the base class are serialized. What can I use instead of "this" to pass to the Json serializer so that it will refer to the instance of the derived class.

Derived class may look like this:

public class Derived : Base
{
     public int Property2 { get; set; }
}

I then call the Serialize() method like this:

Derived derived = new Derived();
string json = derived.Serialize();

Only Property1 is serialized.

Sandy
  • 1,284
  • 2
  • 14
  • 32
  • How you are calling serialize() method from drived call ?? – Zeeshan Feb 27 '20 at 06:15
  • Derived derived = new Derived(); string json = derived.Serialize(); – Sandy Feb 27 '20 at 06:16
  • 1
    I used JsonConvert.SerializeObject(this); of Newtonsoft.Json instead of Text.Json.JsonSerializer and i am able to serialize both porperty Here is my json output : {"Property2":2,"Property1":1} – Zeeshan Feb 27 '20 at 06:33
  • [You can read this question](https://stackoverflow.com/questions/6348215/how-to-deserialize-json-into-ienumerablebasetype-with-newtonsoft-json-net) Your problem solved in this question. – Muslum Collu Feb 27 '20 at 06:48
  • 1
    Thank you @ZeeCode. I will investigate your code further to determine if this is a bug in System.Text.Json or a difference in behavior between Framework and Core. You have given me a lead. – Sandy Feb 27 '20 at 06:51
  • 1
    It is not a bug, the overload you are using is `Serialize(this, options)`. You should be using `Serialize(this,this.GetType(),options)`. – Mat J Feb 27 '20 at 06:53
  • IF you want to serialize out `Property2` from `Derived` class - then your `Derived` class **must** override the `Serialize` virtual method. Otherwise, the base classes' `Seiralize` method is called, which **of course** only knows about the base classes' properties - so it can only serialize out `Property1` .... the **base class** **CANNOT EVER** access values from a descendant class! It only works the other way around .... – marc_s Feb 27 '20 at 07:06
  • @MatJ If you post your comment as an answer, I will accept it. Thank you. – Sandy Feb 27 '20 at 17:21

3 Answers3

1

The reason of it serialize Property1 only is you didn't override the virtual method in the derived class, So it works only for property1.

Sample:

public abstract class Base
    {
        public int Property1 { get; set; } = 20;

        public virtual void Display()
        {

            MessageBox.Show(Property1.ToString());
        }
    }
public class Derived : Base
    {
        public int Property2 { get; set; } = 9;
        public override void Display() //without this you can't achieve what you want
        {
            base.Display();
            MessageBox.Show(Property2.ToString());

        }

    }

public class Test
    {
        public void ShowResult()
        {
            Derived derived = new Derived();
            derived.Display();
        }
    }


Test test = new Test();
{
  test.ShowResult();
}

OUTPUT

Two Messageboxes

First displays: 20

Second displays: 9

If I didn't override the virtual method in the derived class the OUTPUT would be:

One Messageboxe ONLY

Displays: 20

From Documentation

When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member.

Ebrahim ElSayed
  • 157
  • 2
  • 10
1

we can't change 'this' behavior, but you can try below solution, its work like what you need

    class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();

        Console.WriteLine(d.Serialize());
        Console.ReadLine();
    }
}
public abstract class Base
{
    public int Property1 { get; set; }
}
public class Derived : Base
{
    public int Property2 { get; set; }
}

public static class Extensions
{
    public static string Serialize(this Base obj)
    {
        return System.Text.Json.JsonSerializer.Serialize((object)obj);
    }
}
Mehrdad
  • 1,523
  • 9
  • 23
0

The overload method you are using is Serialize< BaseClass >(this, options). This when called from the base class always pass the BaseType as T.

Fortunately, JsonSerializer provides another overload which you can use from baseclass and achieve the desired behavior without overriding in derived class. For this, You should be using Serialize(this,this.GetType(),options). this.GetType() wil always returns the instance type even when call is done from a base class.

Mat J
  • 5,422
  • 6
  • 40
  • 56