0

My application reads in JSON from disk and deserialising using JSON.net; which is working fine.

My JSON is laid out like this:

{
  "driver": {
    "driverTag": "blah_blah",
    "driverName": "Blah Blah",        
    "driverTransport": "serial-device"
  },
  "devices": [
    {
      "deviceName": "Dev1",
      "deviceTag": "DEV1",
      "deviceStartMode": "Auto"         
    },
    {
      "deviceName": "Dev2",
      "deviceTag": "DEV2",
      "deviceStartMode": "Auto"          
    }
  ]
}

Based on the "driverTransport" value, I deserialise to either a SerialDriverConfig, TelnetDriverConfig, SNMPDriverConfig... etc class.

As the "driver" properties will be the same for every driver, no matter the transport type, I have a "DriverConfigTemplate" class. The "devices" will differ from JSON file to JSON file and have specific properties for that transport type (i.e. a serial device will have properties like "serialPortName", "serialBaudRate" etc.)

I have a "DriverConfig" interface, where T is "DeviceConfig".

public interface DriverConfig<T> where T : DeviceConfig
{
    DriverConfigTemplate driver { get; set; }
    List<T> devices { get; set; }
}

My device config is as follows:

public class DeviceConfig : IDeviceConfig
{
    public string deviceTag { get; set; }
    public string deviceName { get; set; }
    public string deviceStartMode { get; set; }
}

Now; the problem part. When I am deserialising, I check the transport type before hand and determine the class to use; i.e for a serial driver I will use the "SerialDriverConfig" class and deserialise using the "SerialDeviceConfig":

public class SerialDeviceConfig : DeviceConfig
{
    public int serialComPort { get; set; }
    public int serialBaudRate { get; set; }
    public int serialDataBits { get; set; }
    public string serialParity { get; set; }
    public string serialStopBits { get; set; }
    public string serialHandshake { get; set; }
    public int serialReadTimeout { get; set; }
    public int serialWriteTimeout { get; set; }
    public bool serialRtsEnable { get; set; }
    public bool serialDtrEnable { get; set; }
}

My "SerialDriverConfig" class looks like this:

public class SerialDriverConfig : DriverConfig<SerialDeviceConfig>
{
    public DriverConfigTemplate driver { get; set; }
    public List<SerialDeviceConfig> devices { get; set; }
}

Again, this is fine and the JSON.net deserialiser does its job perfectly.

I have a function that gets called when the JSON config file has been loaded and validated against its respective schema, then passed on to a "DeserialiseDriverConfig" function where I am trying to return the derived driver object; which is where I am stuck :(

 private DriverConfig<DeviceConfig> DeserialiseDriverConfig(string _json, string _driverTransport)
    {            
        switch (_driverTransport)
        {
            case "serial-device":
                try
                {
                    SerialDriverConfig _serialDriverConfig = JsonConvert.DeserializeObject<SerialDriverConfig>(_json);
                    if (_serialDriverConfig != null)
                    {                            
                        return _serialDriverConfig;
                    }
                }
                catch (Exception e)
                {
                    //Blah blah blah
                }

                break;
        }

        return null;
    }

I have been stuck on this one for a few days, have tried many things and this is where I have ended up. I am getting "Cannot implicitly convert type "SerialDriverConfig" to "DriverConfig". An explicit conversion exists (are you missing a cast?)" So I understand why this error is occurring, but cannot get around it.

Hope my code makes sense and someone can help me out here?

Ash Rowe
  • 39
  • 1
  • 7
  • So how DriverConfigTemplate and IDeviceConfig defined ? For your example you can not return base type unless its a interface (Interface and Interface are different types) You should directly return derived type. – Cihan Uygun Oct 04 '16 at 06:35

2 Answers2

1

I'm not sure if this solution fits your need but if you create your method and SerialDriverConfig with using generic type T you can use your interface as a returning type. Can you try the code below;

Your Method:

private static DriverConfig<T> DeserialiseDriverConfig<T>(string _json, string _driverTransport)
{
    switch (_driverTransport)
    {
        case "serial-device":
            try
            {
                SerialDriverConfig<T> _serialDriverConfig = JsonConvert.DeserializeObject<SerialDriverConfig<T>>(_json);
                if (_serialDriverConfig != null)
                {
                    return _serialDriverConfig;
                }
            }
            catch (Exception e)
            {
                //Blah blah blah
            }

            break;
    }

    return null;
}

SerialDriverConfig Class:

public class SerialDriverConfig<T> : DriverConfig<T>
{
    public DriverConfigTemplate driver { get; set; }
    public List<T> devices { get; set; }
}

Also you should consider changing DriverConfig<T> interface approach because if you leave it as-is you will have boxing issue. If you do not need you may remove where T : DeviceConfig from your interface or modify it according to your current circumstances.

Hope this helps, please let me know if this works for you

Cihan Uygun
  • 2,128
  • 1
  • 16
  • 26
1

You can change your DriverConfig class to be non-generic

public interface DriverConfig 
{
    DriverConfigTemplate driver { get; set; }
    List<DeviceConfig> devices { get; set; }
}

and instead of using derived classes (SerialDriverConfig etc.) you can set Json.net to deserialize to the correct DeviceConfig type based on either having a $type attribute in your JSON like this or using a custom JsonConverter similar to this

Community
  • 1
  • 1
KMoussa
  • 1,568
  • 7
  • 11