JsonSerializer.Serialize only serializes the properties of the base class [duplicate] - c#

This question already has answers here:
Override ToString() is not working in abstract class (.net-core 3.1)
(2 answers)
Closed 2 years ago.
I would like to have a base class that overrides ToString by converting any objects that inherits it to JSON. When running this program, it seems like this in the context of the base object is not the full object, but instead only the base object itself.
Is it possible to refer to the inherited object from the base object?
using System;
using System.Text.Json;
namespace Test
{
public class BaseModel
{
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}
public class Data : BaseModel
{
public string Name { get; set; }
public int Value { get; set; }
}
class Program
{
static void Main(string[] args)
{
var data = new Data { Name = "Test", Value = 42 };
Console.WriteLine(data);
}
}
}

This happens because JsonSerialize.Serialize<TValue>(TValue, [JsonSerializerOptions]) is a generic method, and, due to type interference, your code is compiled as:
public override string ToString()
{
return JsonSerializer.Serialize<BaseModel>(this);
}
In this case, the solution is to use the non-generic overload JsonSerialize.Serialize(object, Type, [JsonSerializerOptions]) instead:
public override string ToString()
{
return JsonSerializer.Serialize(this, this.GetType());
}

You have to define ToString method in the derived class.
public override string ToString()
{
return JsonSerializer.Serialize(this);
}

Related

How to access derived class instance from base class method?

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.
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.
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);
}
}
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.

Bug in .NET framework, reference hidden member using generics [duplicate]

This question already has answers here:
Hide a base class method in a generic derived class
(2 answers)
Closed 5 years ago.
I am thinking that there should be a bug in .NET framework as per the specifications "when we refer object directly instead of using the parent reference it should call the hidden member".
For the same scenario I have used generics but it was not supported for more understanding please go through the code and the output for your reference.
Example code be find here.
public class A
{
public A()
{
Console.WriteLine("A ctor called");
Property=111;
}
public int Property { get; set; }
}
public class B
{
public B()
{
Console.WriteLine("B ctor called");
Property=222;
}
public int Property { get; set; }
}
-----With out Generics-----------
public class Caller
{
public virtual int Property { get; set; }
public Caller()
{
Property=4444;
}
public A GetDevice()
{
return new A();
}
}
public class NextCaller:Caller
{
public NextCaller()
{
Property=5464654;
}
public new B GetDevice()
{
return new B();
}
}
-----With Generics-----------
public interface ReferenceType<TType> where TType:Caller
{
TType GetCurrentType();
}
public class Handler<TType>:ReferenceType<TType> where TType:Caller
{
public virtual TType CurrentObj {get;set;}
public virtual TType GetCurrentType()
{
return CurrentObj as TType;
}
public virtual void Show()
{
var type=GetCurrentType();
Console.WriteLine(CurrentObj.Property);
Console.WriteLine(GetCurrentType().GetDevice().Property);
}
}
public class HandlerNext<TType> : Handler<TType> where TType:NextCaller
{
public override TType CurrentObj {get;set;}
public override TType GetCurrentType()
{
return CurrentObj;
}
}
-------Usage Demo-------------------
public class UsageDemo
{
public void Main()
{
//using generics
var handler=new Handler<Caller>();
handler.CurrentObj=new NextCaller();
handler.Show();
var handler1=new HandlerNext<NextCaller>();
handler1.CurrentObj=new NextCaller();
handler1.Show();
//with out using generics
Caller handle=new NextCaller();
Console.WriteLine(handle.GetDevice().Property);
NextCaller handle1=new NextCaller();
Console.WriteLine(handle1.GetDevice().Property);
}
}
Output:-
//using generics
A ctor calledenter code here
111
A ctor called
111
//with out using generics
A ctor called
111
B ctor called
222
Problem here is,
out of those four outputs 2nd out put showing the wrong result because I have deduce the results using generics. If we see result in the output without using the generics it working correctly (refer output 4).
As per the specifications when we refer object directly instead of using the parent reference it should call the hidden member.
The above specification is not working when we use generics.
Because your show method is in the Handler<TType>, it can only access methods and properties of the type Caller because of the :Caller constaint. It cannot access methods from the type NextCaller.
If you create an override for the .Show method in the HandlerNext class with the exact same method body, it will call methods based on the NextCaller type because of the :NextCaller constraint on that class.

Dynamically create instance of a class which is derived from an abstract class [duplicate]

This question already has answers here:
How to create instance of inherited in static base method?
(3 answers)
Closed 6 years ago.
I have 2 classes which are derived from an abstract class
abstract class Order
{
public virtual boolean Export()
{
...
}
}
class TradeOrder : Order
{
public override bool Export()
{
//Create a new order
}
}
class LibraryOrder : Order
{
public override bool Export()
{
//Dont create order but Update an existing order
}
}
TradeOrder is created for customertype "Trade" and LibraryOrder is created for customertype "Library".
The customer type will grow in near future.
How do I create instance of the derived class based on the customer type without using if...else or swicth ...case?
The instance of the class will call the export method to either create or update a sales order.
-Alan-
Here is one way to achieve what you want. We can call it "convention over configuration approach" since, obviously, your derived order type names and your enum names have to match.
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var customerType = CustomerType.Library;
var order = (Order)Activator.CreateInstance("ConsoleApplication2", "ConsoleApplication2." + customerType.ToString() + "Order").Unwrap();
}
}
public enum CustomerType
{
Trade,
Library
}
public abstract class Order
{
public virtual void Export() { }
}
public class TradeOrder : Order
{
public override void Export() { }
}
public class LibraryOrder : Order
{
public override void Export() { }
}
}
I suggest have a map of object type name and Type and create instance based on the mapping. The mapping details can be initialized in the code or from external source (Ex. Config file).
enum OrderType
{
TradeOrder,
LibraryOrder
}
Dictionary<OrderType, Type> _orderTypeMap = new Dictionary<OrderType, Type>
{
{ OrderType.LibraryOrder, typeof(LibraryOrder)},
{ OrderType.TradeOrder, typeof(TradeOrder)}
};
Order GetOrderInstance(OrderType orderType)
{
return Activator.CreateInstance(_orderTypeMap[orderType]) as Order;
}

How to properly define and call a method on a derived class in C# with an unknown type parameter

I am trying to define a "Transformation" class that will be responsible for returning a simplified array object based on a complex type. The class will accomplish this via a "transform" method that accepts the complex type. This is based on Fractal (http://fractal.thephpleague.com/transformers/), but I am trying to implement something similar in C#.
So far, I have defined an abstract base TransformerAbstract class that contains some properties and methods common to every derived transformer class:
public abstract class TransformerAbstract
{
public abstract object transform(object entity);
}
I am struggling with how to implement the transform method, because I need to know what the complex type is so I can create the transformation, which will be different for every derived transformation class (for example: CycleTransformer, etc.)
public class CycleTransformer : TransformerAbstract
{
public override object transform(object entity)
{
throw new NotImplementedException();
}
}
I have several other places in my applicationwhere I want to be able to transform the data - for example, take the following snippet:
protected object[] fireTransformer(TransformerAbstract transformer, object data)
{
var includedData = new object();
var transformedData = transformer.transform(data);
if (transformerHasIncludes(transformer))
{
includedData = fireIncludedTransformers(transformer, data);
//serialize & merge includes
}
object[] returnData = new object[1];
returnData[0] = transformedData;
returnData[1] = includedData;
return returnData;
}
I appear to have two problems:
I can't mark the method as abstract because I need to know the entity type.
If I mark the method as virtual then the code always calls the base class instead of the derived one, even though I can see at run time via debugging that the correct instance of the class is generated.
I tried using generics early on (e.g. TransformerAbstract<T> : ITransformer<T>) but that forced me to supply a type constraint on any class that uses TransformerAbstract, which I thought was overly restrictive.
I'd probably stop using object and instead use interfaces.
interface ITransformResult<T>
{
}
interface ITransformable<T>
{
}
interface ITransformInclude<T>
{
}
interface ITransformer<T>
{
ITransformResult<T> Transform(ITransformable<T> data);
bool HasIncludes { get; }
IEnumerable<ITransformInclude<T>> FireIncludes(ITransformable<T> data);
}
class TransformedData<T>
{
public ITransformResult<T> Result { get; set; }
public IEnumerable<ITransformInclude<T>> Includes { get; set; }
}
Now that you have a strongly typed structure your function would be as simple as:
protected TransformedData<T> fireTransformer<T>(ITransformer<T> transformer,
ITransformable<T> data)
{
return new TransformedData<T>
{
Result = transformer.Transform(data),
Includes = transformer.HasIncludes
? transformer.FireIncludes(data)
: null
};
}
I am not sure this works for your case or not. You can try virtual and override keywords.
public abstract class TransformerAbstract
{
public virtual object transform(object entity);
}
public class CycleTransformer : TransformerAbstract
{
public override object transform(object entity)
{
throw new NotImplementedException();
}
}
Have a look at below code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
class A
{
public virtual void show()
{
Console.WriteLine("Base Class!");
Console.ReadLine();
}
}
class B : A
{
public override void show()
{
Console.WriteLine("Derived Class!");
Console.ReadLine();
}
}
class Polymorphism
{
public static void Main()
{
A a2 = new B();
a2.show(); // calls derived class.
}
}
}
Would this do what you need?
public class CycleTransformer : TransformerAbstract
{
public override object Transform(object entity)
{
if (entity is CycleData)
{
// Do transform
}
else if (entity is FireData)
{
// Do transform
}
else
{
throw new NotImplementedException();
}
}
}

How to have a list of ProblemBase<TResult>? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I create a list of objects that inherit from the same generic class with varying types?
I'm using several objects where they are inherited from an abstract class. But to use the abstract class must be declara a generic datatype.
I'm having problems because I need to have a list where contains a list of ProblemBase, although each one contains a different TResult datatype.
public abstract class ProblemBase<TResult>
{
TResult[] Array;
}
And I want to get Array property. That's the problem.
This type of thing happens for me quite often. The solution I typically go with is to have a base class for ProblemBase<T> that is type free:
public abstract class ProblemBase
{
public abstract object Result { get; }
}
public abstract class ProblemBase<TResult> : ProblemBase
{
public override object Result
{
get { return Result; }
}
new public TResult Result { get; private set; }
}
Whenever you need a collection of problems, then, you can make a collection of ProblemBase without the generics.
If TResult has its own required inheritance hierarchy, then you can do this instead:
public abstract class ProblemBase
{
public abstract ResultBase Result { get; }
}
public abstract class ProblemBase<TResult> : ProblemBase
where TResult : ResultBase
{
public override ResultBase Result { get { return Result; } }
new public TResult Result { get; private set; }
}

Categories

Resources