A class with a property that can be one of two different types

I am developing a Telegram bot in C #, but I have difficulties with the implementation of the Message type. According to the API documentation , the chat field can be either of type User or of type GroupChat . How to implement this in C #?

So far, I could only come up with the following code using Newtonsoft.Json :

 public class Update { .... [JsonProperty("chat")] public User chat { get; set; } [JsonProperty("chat")] public GroupChat group_chat { get; set; } .... } 

But it does not work with my WebAPI 2 controller, since I am deserializing the Message using the FromBody attribute:

 public async Task<HttpResponseMessage> Post(string token, [FromBody] Update update) 

(type Update has a Message field of type Message )

Is there a better way to implement a Message type?

+5
source share
3 answers

Since you should handle apparently two completely different objects in the same field, I don't think you can use strongly typed objects, but you can use a dynamic type for the chat field, for example

 public class Telegram { public int message_id { get; set; } public dynamic chat { get; set; } } 

Then you can access the variables and check if they are empty or do not understand if this is a user or group chat:

 static void Main(string[] args) { string json = @"{ ""chat"": { ""id"": 1, ""first_name"": ""my_first_name"", ""last_name"": ""my_last_name"", ""username"": ""my_username"" }, ""message_id"": 123 }"; var telegram = Newtonsoft.Json.JsonConvert.DeserializeObject<Telegram>(json); string name = telegram.chat.first_name; // name = my_first_name string title = telegram.chat.title; // title = null } 
+2
source

I ran into this problem in Java as well. Since both C # and Java are strong typed languages, my problem was similar. I solved this by creating a generic Chat class. This Chat class contains properties from User as well as from GroupChat . The class also has the methods isUser() , isGroupChat() , asUser() and asGroupChat() .

I must admit that I do not have knowledge of C #, so I can not write an example in this language for you, but here is the body of the Chat class in Java:

 @SerializedName("id") private int id; @SerializedName("first_name") private String firstName; @SerializedName("last_name") private String lastName; @SerializedName("username") private String username; @SerializedName("title") private String title; public boolean isUser() { return title == null; } public boolean isGroupChat() { return !isUser(); } public User asUser() { return new User(id, firstName, username, lastName); } public GroupChat asGroupChat() { return new GroupChat(id, title); } 

This is pretty verbose and adds repeating code, so if anyone has any add-ons, I would also like to hear them.

0
source

You can create your Message type as an interface ( IMessage ), and then implement it using the GroupMessage and UserMessage .

 interface IMessage { int id; //... object chat {get;} } public class GroupMessage : IMessage { public int id; public GroupChat group; public object chat {get {return group;} } } public class UserMessage : IMessage { public int id; public User user; public object chat {get {return user;} } } 

But what I really do is deal with this at a higher level. If you look at the documents here, and not at a complex object that can handle all this, I would think in terms of sending or receiving a message. Then I would think about all the actions that you might want to do when you receive a message. From there, I will have an object that can raise an event for each of these actions. When you receive data (do not think of it as a message), you analyze the data and, possibly, raise several events from what was one object of the Telegram message. Some of these events may require class definitions for the data needed for the event, but now we are talking about something much narrower in scope; better suited to the principle of shared responsibility.

Going in the other direction (sending data, not receiving), the object will have methods for different types of things that you can do when sending data. Some of these methods may require classes for the required data. Whenever possible, use the same classes as for receiving events. It could even be one Send() method with many overloads.

0
source

All Articles