Home > database >  How to create a C# class with 'flexible' properties?
How to create a C# class with 'flexible' properties?

Time:08-08

I'm trying to write a JSON file, which consists in a series of questions, that each have basically the following structure:

{
        "values": [
            "oui"
        ],
        "question": "h_d",
        "type": "radio",
        "conditions": {
            "lhs": {
                "question": "valeur_wed"
            },
            "operator": "eq",
            "rhs": 0
        },
        "conditionalInfo": []
    },

What I do to produce the JSON file is to have a JSONQuestion class, for which I create a new instance for every question and I provide the different values for the properties. Then I do a JsonSerializer.Serialize(list_of_JSONQuestion_instances) in order to get my JSON text file (using System.Text.Json).

Now, this all works fine, except that the "conditions" element in every question should actually be more flexible. For instance, the "lhs" (and/or the "rhs") could itself contain a whole other condition, like this:

{
        "values": [],
        "question": "calcul_wed_rugosite_cp",
        "conditions": {
            "lhs": {
                "lhs": {
                    "question": "valeur_wed"
                },
                "operator": "eq",
                "rhs": "calcule"
            },
            "operator": "and",
            "rhs": {
                "lhs": {
                    "question": "calcul_h_sur_d_script"
                },
                "operator": "eq",
                "rhs": 1
            }
        },

And it could even go deeper, with more levels of lhs and rhs. So, the lhs and rhs of each question can be of varying complexity.

My question is therefore: How can I create some sort of Condition class that would have 3 properties (lhs, rhs, and operator), but 'flexible'? Sometimes the rhs is just a string or an int, but sometimes it's a whole new Condition istelf. Same for lhs.

Is it feasible at all?

I was thinking using this:

public class Condition<L, R>
    where L : class
    where R : class
   {
        public L lhs { get; set; }
        public string @operator { get; set; }
        public R rhs { get; set; }
    }

...but then how do I declare the 'conditions' property in my main JSONQuestion class? As I obviously can't do this:

public class JSONQuestion
{
    public string question { get; set; }
    public Condition<L, R> conditions { get; set; }
    ...
}

CodePudding user response:

You could use the [JsonExtensionData] attribute. It allows you to declare a dictionary-property that you analyze after deserialization to see what it contains. We use it primarily when we need to embed JSON-data inside our own JSON.

If you are using Newtonsoft.JSON:
https://www.newtonsoft.com/json/help/html/DeserializeExtensionData.htm

If you are using .NET's JSON impl.:
https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-handle-overflow?pivots=dotnet-6-0

CodePudding user response:

I generally try to avoid custom (de)serialisers so I'm biased towards solutions that don't use them.

I would have data structure like this:

public class Node
{
   public string? Type{ get; set; } // This decide what other values mean
   public string? Value { get; set; }
   public Node Lhs? { get; set; }
   public string? Operator { get; set; }
   public Node? Rhs { get; set; }
}

This is very unsophisticated but allows to represent the trees you shown.

The json would be something like this:

{
    "Type": "Question",
    "Value": "calcul_wed_rugosite_cp",
    "Lhs": {
        "Lhs": {
            "Type": "Question",
            "Value": "valeur_wed"
        },
        "Operator": "eq",
        "Rhs": {
            "Type": "calcule",
            "Value": "I'm not sure how 'calcule' condition works" 
        }
    },
    "Operator": "and",
    "Rhs": {
        "Lhs": {
            "Type": "Questions",
            "Value": "calcul_h_sur_d_script"
        },
        "Operator": "eq",
        "Rhs": {
            "Type": "Value",
            "Value": "1"
        }
    }
}
  • Related