3

I'm using LitJson and BestHTTP libraries on a Unity3D project and I would write my custom ResponseSerializer object. The goal is create a method that uses generics to map the possible response into my wanted object.

So, my first attempt was something similar:

public static void SerializeResponse<T>(string error, HTTPResponse response, string insideKey, Action<APIResource<T>> callback)
    where T:new()
{
    var apiResource = new APIResource<T>();

    if (error != null)
    {
        apiResource.error = error;
    }
    else
    {
        apiResource.error = null;
        JsonData jsonData = JsonMapper.ToObject(response.DataAsText);
        apiResource.resource = (T)(jsonData[insideKey]);
    }
    callback(apiResource);
}

But in this way I get compiling error on the

apiResource.resource = (T)(jsonData[insideKey]);

with message:

Cannot convert type LitJson.JsonData to T

The possible types of needed T are only 4 (at the moment):

  • string
  • int
  • float
  • bool

So, I started playing with switch on type but everytime I get compiling error. My last attempt was this (taken from https://stackoverflow.com/a/4478535/2838073) :

public static void SerializeResponse<T>(string error, HTTPResponse response, string insideKey, Action<APIResource<T>> callback)
    where T:new()
{
    var apiResource = new APIResource<T>();

    if (error != null)
    {
        apiResource.error = error;
    }
    else
    {
        apiResource.error = null;
        JsonData jsonData = JsonMapper.ToObject(response.DataAsText);

        var @switch = new Dictionary<Type, Action> {
            { typeof(string),   () => { apiResource.resource = (string)jsonData[insideKey]; } },
            { typeof(int),      () => { apiResource.resource = (int)jsonData[insideKey]; } },
            { typeof(float),    () => { apiResource.resource = (float)jsonData[insideKey]; } },
            { typeof(bool),     () => { apiResource.resource = (bool)jsonData[insideKey]; }}
        };

        @switch[typeof(T)]();
    }
    callback(apiResource);
}

But the error is always the same:

Cannot implicitly convert type mytype to T

What am I doing wrong? I'm not pratical on C# with generics pattern and I would to learn from my mistakes.

2 Answers2

2

As T includes both value-types (e.g. int) and reference-types (string) you need to box the value returned from jsonData[insideKey] before by casting to object:

apiResource.resource = (T)(object)(jsonData[insideKey]);
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Hi HimBromBeere, I did as you suggested but when I use **.SerializeResponse(...)** I get the following error: `The type "string" must have a public parameterless constructor in order to use it as parameter "T" in the generic type or method...` – Alessio Zap Boerio Oct 02 '17 at 10:24
  • ok, my fault. I defined T as instantiable with newT(). Thank you – Alessio Zap Boerio Oct 02 '17 at 10:26
  • No, I get a crash in runtime during the cast with error: `Ex [HTTPRequest]: CallCallback - Message: 1: Cannot cast from source type to destination type. at <0x00000> ` – Alessio Zap Boerio Oct 02 '17 at 10:42
0

Isn't something like this would be good? I used your first code, but instead of a type-cast, it will create a new json string and will use the generic ToObject to try to create the final object:

public static void SerializeResponse<T>(string error, HTTPResponse response, string insideKey, Action<APIResource<T>> callback) where T : new()
{
    var apiResource = new APIResource<T>();

    if (error != null)
    {
        apiResource.error = error;
    }
    else
    {
        apiResource.error = null;
        JsonData jsonData = JsonMapper.ToObject(response.DataAsText);
        apiResource.resource = JsonMapper.ToObject<T>(jsonData[insideKey].ToJson());
    }
    callback(apiResource);
}

Unfortunately, it's an additional object->json string->object conversion, thought. But at least it should work.

Ben
  • 1,023
  • 9
  • 10