I have a converter class that receives json in input, here are 2 valid examples:

{
  "method": "Model",
  "payload": {
    "key": "value"
  }
}

and

{
  "method": "OtherModel",
  "payload": {
    "foo": "bar"
  }
}

In C#, I have classes mapped to each possible model:

public class Model
{
  public string Key { get; set; }
}

public class OtherModel
{
  public string Foo { get; set; }
}

I need a generic converter

How can I use the string value in the method of the JSON to convert in a generic way the content of the payload field?

Is using a huge switch the only way? This is the prototype I have so far but there are hundreds of different models so it will grow quite large...

public IResult ParseJson(string json)
{
  Regex regexMessageName = new Regex("\"messageName\": \"(.*?)\"", RegexOptions.Compiled);
  var messageName = regexMessageName.Match(json).Groups[1].Value;
  switch (messageName)
  {
    case "Model":
      var raw = JsonConvert.DeserializeObject<JsonData<Model>>(json);
      return new LogInfoRequestResult<Model> { Raw = raw };
    case "OtherModel":
      var raw = JsonConvert.DeserializeObject<JsonData<OtherModel>>(json);
      return new LogInfoRequestResult<OtherModel> { Raw = raw };

  }
}

If you want complete control of your classes, and allow them to evolve independently, then you can have one base class that owns the Method, and then as many subclasses as you want with their own definition of the payload.

First, parse into the baseclass, just to get a strongly typed deserialization of Method

Then, there are a lot of patterns to address branching logic.

  • If you have 1-2 cases, an if statement is fine
  • If you have 3-5 cases, you can use a switch
  • If you have 6-10 cases, you can create a dictionary that maps method name to class type
  • If you have more than that, you can use the strategy pattern and pass an interface around

Here's an example of how you could write the code:

var json = @"{
    'method': 'Model',
    'payload': {
        'key': 'value'
    }
}";

var modelBase = JsonConvert.DeserializeObject<ModelBase>(json);

var methodMapping = new Dictionary<string, Type>()
{
    {MethodTypes.Model.ToString(), typeof(Model)},
    {MethodTypes.OtherModel.ToString(), typeof(OtherModel)},
};
            
Type methodClass = methodMapping[modelBase.Method];

var result = JsonConvert.DeserializeObject(json, methodClass);

Note: Since we're programmatically determining the correct type, it's hard to pass to a generic <T>, so this uses the overload of DeserializeObject that takes type as a param

And here are the classes that model incoming messages

public enum MethodTypes
{
    Model,
    OtherModel
}

public class ModelBase
{
    public string Method { get; set; }
}

public class Model : ModelBase
{
    public ModelInfo Payload { get; set; }

    public class ModelInfo
    {
        public string Key { get; set; }
    }
}

public class OtherModel : ModelBase
{
    public ModelInfo Payload { get; set; }

    public class ModelInfo
    {
        public string Foo { get; set; }
    }
}

Dictionary<string,string>

If your data is always going to be "foo":"bar" or "key":"value" .... string:string, then Cid's suggesting to use Dictionary<string,string> Payload makes a lot of sense. Then figure out however you want to map from that c# class in a c# constructor that returns whatever type you want.

Additional Resources: