1

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;
        }                    
    }
}
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • possible duplicate of [How to dynamically create generic C# object using reflection?](http://stackoverflow.com/questions/1151464/how-to-dynamically-create-generic-c-sharp-object-using-reflection) – Yurii Feb 28 '14 at 09:42
  • Is `ReadJsonResponseAs` an extension method? Is that defined in a third-party library? Check whether the API exposes an overload that takes a `Type` object instead of a generic type parameter. – dcastro Feb 28 '14 at 09:43
  • 3
    Not a duplicate of that. This is calling a generic method. – Andrew Feb 28 '14 at 09:43
  • @dcastro added the code for ReadJsonResponseAs –  Feb 28 '14 at 09:46
  • @user3357776 Does those types read dynamically, implement common interface? – Leri Feb 28 '14 at 09:50
  • @Leri No, it is a single type with dynamically varying number of other different types in it. –  Feb 28 '14 at 10:20

4 Answers4

2

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.

dcastro
  • 66,540
  • 21
  • 145
  • 155
1

MethodInfo.MakeGenericMethod serves this purpose.

Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
0

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.

Andrew
  • 8,322
  • 2
  • 47
  • 70
0

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);
chridam
  • 100,957
  • 23
  • 236
  • 235