Search code examples
c#genericsgeneric-type-argument

Conditional type argument in C#


I would like to deserialize object into a given class type, depending on whether the ajax response was successful or not.

So I written the following method:

public IAjaxResponse GetResponse<TOk, TFail>()
{
    var responseJson = this.response as Dictionary<string, object>;

    object obj = null;

    if ((string)responseJson["status"] == "ok")
        obj = JsonConvert.DeserializeObject<TOk>(responseJson);
    else
        obj = JsonConvert.DeserializeObject<TFail>(responseJson);

    return (IAjaxResponse)obj;
}

Now it's pretty straightforward to use:

var response = GetResponse<ClassWhenOk, ClassWhenFail>();
if (response is ClassWhenFail responseFail) {
    Error.Show(responseFail.message);
    return;
}
[..]

Now my problem is: sometimes, there are generic responses which happend to be always 'ok' status so I don't want to use the second type argument for failed status.

So I would want to use something like that:

               \/ notice one type argument
GetResponse<ClassWhenOk>();

This is not allowed though since using this generic method requires 2 type arguments.

So here comes my question:

Can I somehow mark the second type argument (TFail) as 'not required'? Or should I rather go for different approach?


Solution

  • Your code just doesn't make sense. The responseJson object cannot be a Dictionary<string, string> and a string at the same time. It would be good to be able to post real code for us to work from.

    Here's a refactored example that does compile, but needs some work to behave properly at run-time. Nevertheless, all you need is an alternative overload to make this work.

    public IAjaxResponse GetResponse<TOk, TFail>(string response)
    {
        var responseJson = new Dictionary<string, object>();
    
        object obj = null;
    
        if ((string)responseJson["status"] == "ok")
            obj = Newtonsoft.Json.JsonConvert.DeserializeObject<TOk>(response);
        else
            obj = Newtonsoft.Json.JsonConvert.DeserializeObject<TFail>(response);
    
        return (IAjaxResponse)obj;
    }
    
    public IAjaxResponse GetResponse<TOk>(string response)
    {
        return (IAjaxResponse)Newtonsoft.Json.JsonConvert.DeserializeObject<TOk>(response);
    }
    

    The second method could even be this:

    public IAjaxResponse GetResponse<TOk>(string response)
    {
        return GetResponse<TOk, FailDontCare>(response);
    }
    

    That just avoids code duplication.