user3357776
user3357776

Reputation:

A Type created at runtime as a Type Parameter for a Generic Type

I have this senario where I need to provide a type for json deserialization, how do I make it dynamic?

Here the code uses an example class name(rd.ds.SDK.re.sa), but in the real code the type will be constructed using data from database.

Type dynamicalyCreatedAtRuntime = Type.GetType("rd.ds.SDK.re.sa");

var response = webRequest.ReadJsonResponseAs<Result<AnalysisResult<dynamicalyCreatedAtRuntime>>();


public static T ReadJsonResponseAs<T>(this HttpWebRequest webRequest)
{
    using (System.IO.Stream responseStream = webRequest.GetResponse().GetResponseStream())
    {
        using (System.IO.StreamReader sr = new System.IO.StreamReader(responseStream))
        {
            T result = JsonConvert.DeserializeObject<T>(sr.ReadToEnd());

            responseStream.Close();
            return result;
        }                    
    }
}

Upvotes: 1

Views: 105

Answers (4)

dcastro
dcastro

Reputation: 68660

Use this overload of JsonConvert.DeserializeObject instead:

public static object ReadJsonResponseAs(this HttpWebRequest webRequest, Type type)
{
    using (System.IO.Stream responseStream = webRequest.GetResponse().GetResponseStream())
    {
        using (System.IO.StreamReader sr = new System.IO.StreamReader(responseStream))
        {
            object result = JsonConvert.DeserializeObject(sr.ReadToEnd(), type);

            responseStream.Close();
            return result;
        }                    
    }
}

Obviously, you'll need to treat the result as an object. Since you won't know the type of the object during compile-time, there's no point in using generics or using reflection to invoke the generic overload.


You should also create a non generic version of these types: Result<T> and AnalysisResult<T>.

Having to dynamically create types such as Result<AnalysisResult<dynamicalyCreatedAtRuntime>> at runtime could be done with reflection, but there would be 0 benefits in doing so. This screams for a redesign.

Upvotes: 2

chridam
chridam

Reputation: 103365

Use reflection to get the method to start with, then "construct" it by supplying type arguments with MakeGenericMethod:

Type dynamicalyCreatedAtRuntime = Type.GetType("rd.ds.SDK.re.sa");
MethodInfo method = webRequest.GetType().GetMethod("ReadJsonResponseAs");
MethodInfo generic = method.MakeGenericMethod(dynamicalyCreatedAtRuntime );
generic.Invoke(this, null);

Upvotes: 0

Andrew
Andrew

Reputation: 8674

If you can, I would use Netwonsoft.JSON (Json.Net) for this.

var json = ...get request body...
var type = Type.GetType("a.b.c");
var obj  = JsonConvert.DeserializeObject(json, type);

Lots of help out there for working with Json.NET too. This may not work if you aren't in control of the classes, and they need custom conversions.

If you absolutely must call the Generic method, you are going to need to use reflection to manually construct the call. This gets tricky, and probably isn't worth it.

var m = webRequest.GetType().GetMethod("ReadJsonResponseAs");
var func = m.MakeGenericMethod(type);
func.Invoke(webRequest, null); /* invoke func on webRequest object, no params */

Are your generic types that deeply nested? If so you will probably have to make each level separately.

Upvotes: 0

Ondrej Tucny
Ondrej Tucny

Reputation: 27962

MethodInfo.MakeGenericMethod serves this purpose.

Upvotes: 1

Related Questions