Is there a better way to turn a JObject into any interface implementation?

I am not sure if there is a better way to do this. maybe someone will help?

I want to pass an object of type JObject to a class in factory. The class itself must be decided based on another parameter. But I can only think about serializing the object to a string, serializing back to a specific class. Should there be a better way?

https://dotnetfiddle.net/3Qwq6V

 using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; namespace Test { public class Input { public int TypeId { get; set; } public object ObjectDefinesInput; } public class VoiceInput { public string Language; } public class TextInput { public string Encoding; } public interface IResponse { void Respond(); } public class VoiceResponse : IResponse { private VoiceInput input { get; set; } public VoiceResponse(VoiceInput input) { this.input = input; } public void Respond() { // use information on VoiceInput to do something Console.WriteLine("(In "+ this.input.Language +"): beep buup boop."); } } public class TextResponse : IResponse { private TextInput input { get; set; } public TextResponse(TextInput input) { this.input = input; } public void Respond() { Console.WriteLine("I am a text handler. Using "+ this.input.Encoding +"."); } } public static class ResponseFactory { public static IResponse CreateResponseHandler(Input input) { // ----------------- ISSUE HERE -----------------------------// // I'm using JsonConvert to serialize an <object> to a string, and then string jsonObjectDefinesInput = JsonConvert.SerializeObject(input.ObjectDefinesInput, new JsonSerializerSettings { Formatting = Formatting.Indented, ContractResolver = new CamelCasePropertyNamesContractResolver() }); switch (input.TypeId) { case 1: // (VoiceInput) input.ObjectDefinesInput throws exception // input.ObjectDefinesInput as VoiceInput returns null VoiceInput voiceInput = JsonConvert.DeserializeObject<VoiceInput>(jsonObjectDefinesInput); return new VoiceResponse(voiceInput); default: TextInput textInput = JsonConvert.DeserializeObject<TextInput>(jsonObjectDefinesInput); return new TextResponse(textInput); } } } public class Program { public static void Main(string[] args) { string jsonData1 = "{ \"typeId\": 1, \"ObjectDefinesInput\": { \"Language\": \"Robot\" } }"; string jsonData2 = "{ \"typeId\": 2, \"ObjectDefinesInput\": { \"Encoding\": \"UTF-8\" } }"; Input someInpput1 = JsonConvert.DeserializeObject<Input>(jsonData1); Input someInpput2 = JsonConvert.DeserializeObject<Input>(jsonData2); IResponse testResponse1 = ResponseFactory.CreateResponseHandler(someInpput1); IResponse testResponse2 = ResponseFactory.CreateResponseHandler(someInpput2); testResponse1.Respond(); testResponse2.Respond(); Console.ReadLine(); } } } 
+5
source share
2 answers

Hmm, since I found that the type is actually a JObject (since I am deserializing to <object>, the base class of JObject), then I can do

 input.ObjectDefinesInput.ToObject<TextInput>(); 

according to Convert JToken (or string) to the specified type

+1
source

If you just specified the correct input type, you can use them:

 var voiceInput = new Input() { TypeId = 1, ObjectDefinesInput = new VoiceInput(){ ... } } 

and

 switch (input.TypeId) { case 1: VoiceInput voiceInput = (VoiceInput)input.ObjectDefinesInput; return new VoiceResponse(voiceInput); default: TextInput textInput = (textInput)input.ObjectDefinesInput; return new TextResponse(textInput ); } 

If you need security of a particular type, have your Input class have a general type argument for the input type

 public class Input<T> { public int TypeId { get; set; } public T ObjectDefinesInput; } 

AND

 var voiceInput = new Input<VoiceInput>() { TypeId = 1, ObjectDefinesInput = new VoiceInput(){ ... } } 

Then casting is not required:

 switch (input.TypeId) { case 1: return new VoiceResponse(input.ObjectDefinesInput); default: return new TextResponse(input.ObjectDefinesInput); } 
+2
source

Source: https://habr.com/ru/post/1271431/


All Articles